package com.spsoft.vatoutinv.service.vmsfulloutinvoice.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.spsoft.core.config.VmsCommonProperties;
import com.spsoft.core.enums.ResponseEnum;
import com.spsoft.core.exception.BusinessException;
import com.spsoft.core.listener.ExcelListener;
import com.spsoft.core.model.Result;
import com.spsoft.core.model.bo.TokenUser;
import com.spsoft.core.utils.*;
import com.spsoft.system.entity.*;
import com.spsoft.system.mapper.NvatOutInvoiceDetailsMapper;
import com.spsoft.system.mapper.NvatOutInvoiceItemsMapper;
import com.spsoft.system.mapper.NvatOutInvomapselfMapper;
import com.spsoft.system.mapper.NvatRevmapinvoitemsMapper;
import com.spsoft.system.service.DefBizdictService;
import com.spsoft.system.service.NvatNegativestreamService;
import com.spsoft.vatoutinv.config.Sm4Properties;
import com.spsoft.vatoutinv.constants.CommonConstant;
import com.spsoft.vatoutinv.constants.DictConstant;
import com.spsoft.vatoutinv.entity.vmscreditlimit.VmsCreditLimit;
import com.spsoft.vatoutinv.entity.vmsenterpriseinfo.VmsEnterpriseInfo;
import com.spsoft.vatoutinv.entity.vmsfullbswjmanager.VmsFullBswjManager;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.webimport.VmsInvoiceExcel;
import com.spsoft.vatoutinv.entity.vmsfulloutinvoice.webimport.VmsInvoiceItemExcel;
import com.spsoft.vatoutinv.entity.vmswebimportfile.VmsWebImportFile;
import com.spsoft.vatoutinv.enums.*;
import com.spsoft.vatoutinv.mapper.VmsFullOutInvoiceDetailsMapper;
import com.spsoft.vatoutinv.mapper.VmsNvatTrandtadvaltaxsepMapper;
import com.spsoft.vatoutinv.model.dto.statistics.InvoiceInfoDto;
import com.spsoft.vatoutinv.model.dto.vmsenterpriseinforisk.VmsEnterpriseInfoRiskDto;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceDTO;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoiceDownloadDTO;
import com.spsoft.vatoutinv.model.dto.vmsfulloutinvoice.VmsFullOutInvoicePageDTO;
import com.spsoft.vatoutinv.model.vo.statistics.InvoiceInfoVo;
import com.spsoft.vatoutinv.model.vo.vmsenterpriseinforisk.VmsEnterpriseInfoRiskVo;
import com.spsoft.vatoutinv.model.vo.vmsfulloutinvoice.InvoiceDetailItemVO;
import com.spsoft.vatoutinv.model.vo.vmsfulloutinvoice.InvoiceDetailVO;
import com.spsoft.vatoutinv.model.vo.vmsfulloutinvoice.VmsFullOutInvoicePageVO;
import com.spsoft.vatoutinv.service.generateinvoice.GenerateInvoiceService;
import com.spsoft.vatoutinv.service.issueinvoice.CheckDataService;
import com.spsoft.vatoutinv.service.nvatoutinvoice.NvatOutInvoiceService;
import com.spsoft.vatoutinv.service.vmscreditlimit.VmsCreditLimitService;
import com.spsoft.vatoutinv.service.vmsenterpriseinfo.VmsEnterpriseInfoService;
import com.spsoft.vatoutinv.service.vmsenterpriseinforisk.VmsEnterpriseInfoRiskService;
import com.spsoft.vatoutinv.service.vmsfullbswjmanager.VmsFullBswjManagerService;
import com.spsoft.vatoutinv.service.vmsfulloutinvoice.*;
import com.spsoft.vatoutinv.service.vmsfullyfmmessage.VmsFullYfmMessageService;
import com.spsoft.vatoutinv.service.vmshzqrdmanage.VmsHzqrdApplyService;
import com.spsoft.vatoutinv.service.vmswebimportfile.VmsWebImportFileService;
import com.spsoft.vatoutinv.util.ofd.OfdInvoiceUtils;
import com.spsoft.vatoutinv.util.ofd.entity.OriginalInvoice;
import com.spsoft.vatoutinv.util.ofd.entity.base.GoodsInfo;
import com.spsoft.vatoutinv.util.ofd.entity.passenger.PassengerInfo;
import com.spsoft.vatoutinv.util.ofd.entity.passenger.PassengerTransportationInfo;
import com.spsoft.vatoutinv.util.ofd.entity.realestate.RealEstateLeasInfo;
import com.spsoft.vatoutinv.util.ofd.entity.realestate.RealEstateSalesInfo;
import com.spsoft.vatoutinv.util.xml.XmlInvoiceUtils;
import com.spsoft.vatoutinv.util.xml.entity.EInvoice;
import com.spsoft.vatoutinv.util.xml.entity.XMLEntity;
import com.spsoft.vatoutinv.util.xml.entity.einvoicedata.*;
import com.spsoft.vatoutinv.util.xml.entity.header.*;
import com.spsoft.vatoutinv.util.xml.entity.sellerauthentication.SellerAuthentication;
import com.spsoft.vatoutinv.util.xml.entity.taxsupervisioninfo.TaxSupervisionInfo;
import com.spsoft.vms.redis.RedisService;
import com.spsoft.vms.redis.constant.RedisConstant;
import com.spsoft.vms.redis.service.BswjRedisService;
import com.spsoft.vms.redis.service.impl.QueryUploadInvoiceVmsQueueServiceImpl;
import com.spsoft.vms.redis.service.impl.UploadInvoiceVmsQueueServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.ofdrw.converter.export.OFDExporter;
import org.ofdrw.converter.export.PDFExporterIText;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * <p>
 * 数电发票信息表 服务实现类
 * </p>
 *
 * @author chenxudong
 * @since 2023-11-30
 */
@Service
@Slf4j
@RequiredArgsConstructor
@SuppressWarnings("unchecked")
public class VmsFullOutInvoiceDetailsServiceImpl extends ServiceImpl<VmsFullOutInvoiceDetailsMapper, VmsFullOutInvoiceDetails> implements VmsFullOutInvoiceDetailsService {

    public static final String LOG_MSG = "(数电发票信息实现层)";

    private final VmsFullOutInvoiceItemsService fullOutInvoiceItemsService;

    private final VmsFullOutInvoiceItemsExpService fullOutInvoiceItemsExpService;

    private final VmsFullOutInvoiceItemsAddService fullOutInvoiceItemsAddService;

    private final VmsFullOutInvoiceCekcService fullOutInvoiceCekcService;

    private final NvatOutInvoiceService nvatOutInvoiceService;

    private final VmsCreditLimitService creditLimitService;

    private final VmsFullYfmMessageService fullYfmMessageService;

    private final RedisService redisService;

    private final DefBizdictService dictService;

    private final Sm4Properties sm4Properties;

    private final VmsCommonProperties vmsProperties;

    private final VmsEnterpriseInfoService enterpriseInfoService;

    private final VmsFullBswjManagerService fullBswjManagerService;

    private final VmsEnterpriseInfoRiskService vmsEnterpriseInfoRiskService;

    private final NvatRevmapinvoitemsMapper nvatRevmapinvoitemsMapper;

    private final NvatOutInvomapselfMapper nvatOutInvomapselfMapper;

    private final VmsFullOutInvoiceTdywService fullOutInvoiceTdywService;

    private final VmsFullOutInvoiceTdywItemService fullOutInvoiceTdywItemService;

    private final BswjRedisService bswjRedisService;

    private final UploadInvoiceVmsQueueServiceImpl uploadInvoiceVmsQueue;

    private final QueryUploadInvoiceVmsQueueServiceImpl queryUploadInvoiceVmsQueue;

    private final VmsNvatTrandtadvaltaxsepMapper vmsNvatTrandtadvaltaxsepMapper;

    private final NvatOutInvoiceDetailsMapper nvatOutInvoiceDetailsMapper;

    private final NvatOutInvoiceItemsMapper nvatOutInvoiceItemsMapper;

    private final NvatNegativestreamService nvatNegativestreamService;

    private final CheckDataService checkDataService;

    private final VmsWebImportFileService vmsWebImportFileService;

    /**
     * 直连单位id
     */
    @Value("${leqi.zldwId}")
    private String zldwId;

    @Override
    public Result<IPage<VmsFullOutInvoicePageVO>> page(VmsFullOutInvoicePageDTO dto) {
        Integer pageNo = dto.getPageNo();
        Integer pageSize = dto.getPageSize();

        LambdaQueryWrapper<VmsFullOutInvoiceDetails> lq = new LambdaQueryWrapper<VmsFullOutInvoiceDetails>()
                .likeRight(StringUtil.isNotEmpty(dto.getGmfmc()), VmsFullOutInvoiceDetails::getGmfmc, dto.getGmfmc())
                .eq(StringUtil.isNotEmpty(dto.getSjly()), VmsFullOutInvoiceDetails::getSjly, dto.getSjly())
                .likeRight(StringUtil.isNotEmpty(dto.getFphm()), VmsFullOutInvoiceDetails::getFphm, dto.getFphm())
                .eq(StringUtil.isNotEmpty(dto.getFpzt()), VmsFullOutInvoiceDetails::getFpzt, dto.getFpzt())
                .eq(StringUtil.isNotEmpty(dto.getFplxdm()), VmsFullOutInvoiceDetails::getFppz, dto.getFplxdm())
                .eq(StringUtil.isNotEmpty(dto.getSczt()), VmsFullOutInvoiceDetails::getSczt, dto.getSczt())
                .eq(VmsFullOutInvoiceDetails::getQydjid, SecurityUtils.getDeptCode())
                .eq(VmsFullOutInvoiceDetails::getDelFlag, CommonEnum.DEL_STATUS_0.getKey())
                .orderByDesc(VmsFullOutInvoiceDetails::getKprq, VmsFullOutInvoiceDetails::getFoidid);

        if (StringUtil.isNotEmpty(dto.getStartTime())) {
            lq.between(VmsFullOutInvoiceDetails::getKprq, DateUtil.beginOfDay(DateUtil.parseDate(dto.getStartTime())), DateUtil.endOfDay(DateUtil.parseDate(dto.getEndTime())));
        }

        IPage<VmsFullOutInvoicePageVO> page = page(new Page<>(pageNo, pageSize), lq)
                .convert(item -> {
                    VmsFullOutInvoicePageVO vo = new VmsFullOutInvoicePageVO();
                    BeanUtils.copyBeanProp(vo, item);
                    return vo;
                });
        return Result.OK(page);
    }

    public void fileDownload(VmsFullOutInvoiceDownloadDTO dto) {
        // 获取下载发票列表
        String[] fphms = dto.getFphms();
        // 下载类型
        String downloadType = dto.getDownloadType();
        // 下载文件字节流
        byte[] bFile = null;
        // 文件名称
        String fileName = "";
        int fileSize = fphms.length;
        // 文件根地址
        String fileAddress = vmsProperties.fullPath();
        // 文件地址名称
        String filePathAndName = "";
        // 压缩
        String[] filesToCompress = new String[fphms.length];
        try {
            for (int i = 0; i < fileSize; i++) {
                String fphm = fphms[i];
                fileName = "dzfp_" + fphm + "_" + DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
                VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails = this.queryInvoiceInfo(fphm);
                if (ObjectUtil.isNull(vmsFullOutInvoiceDetails)) {
                    throw new BusinessException(ResponseEnum.INVOICE_NOT_FOUND);
                }
                if (CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey().equals(vmsFullOutInvoiceDetails.getSczt())) {
                    throw new BusinessException(ResponseEnum.INVOICE_UPLOAD_STATUS_3_ERROR);
                }
                // 校验当前机构 版式文件生成 是否启用
                boolean flag = fullBswjManagerService.queryStatus(vmsFullOutInvoiceDetails.getQydjid(), CommonEnum.BUSINESS_SWITCH_TYPE_01.getKey());
                if (!flag) {
                    throw new BusinessException(ResponseEnum.BUSINESS_SWITCH_NOT_ENABLE_BSWJ.getCode(), SecurityUtils.getTokenUser().getDeptName() + ResponseEnum.BUSINESS_SWITCH_NOT_ENABLE_BSWJ.getMsg());
                }
                // 销售方纳税人识别号
                String kpnssbh = vmsFullOutInvoiceDetails.getXsfnsrsbh();
                // 判断系统来源 是否需要生成
                String sjly = vmsFullOutInvoiceDetails.getSjly();
                if (CommonEnum.DATA_SOURCE_99.getKey().equals(sjly)) {
                    // 不需要生成 直接去对应目录获取
                    filePathAndName = vmsProperties.webImportLayoutFilePath() + kpnssbh + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "yyyy") + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "MMdd") + File.separator + fphm + "." + downloadType;
                    log.info("系统来源为 web端导入,文件路径：{}", filePathAndName);
                    // 判断文件是否存在
                    File file = new File(filePathAndName);
                    if (!file.exists()) {
                        throw new BusinessException(ResponseEnum.INVOICE_FILE_NOT_FOUND);
                    }
                } else {
                    List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems = this.queryInvoiceDetails(vmsFullOutInvoiceDetails.getFoidid());
                    // 目录 税号 年 月日
                    filePathAndName = fileAddress + kpnssbh + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "yyyy") + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "MMdd") + File.separator + fphm + "." + downloadType;
                    File file = new File(fileAddress + kpnssbh + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "yyyy") + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "MMdd"));
                    if (!file.exists()) {
                        file.mkdirs();
                    }
                    genFile(downloadType, vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems, filePathAndName, vmsFullOutInvoiceDetails.getQydjid());
                }
                filesToCompress[i] = filePathAndName;
                bFile = FileStreamUtil.fileToBytes(filePathAndName);
            }
            // 压缩包
            if (fileSize > 1) {
                // 压缩包文件名
                long tempId = IdWorker.getId();
                fileName = fileAddress + "ziptemp";
                File zipName = new File(fileName);
                if (!zipName.exists()) {//判断文件目录是否存在
                    zipName.mkdirs();
                }
                String zipFileName = fileName + File.separator + "qdfp" + tempId + ".zip";
                try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(Paths.get(zipFileName)))) {
                    // 添加文件到压缩包
                    for (int t = 0; t < fphms.length; t++) {
                        addToZipFile(fphms[t] + "." + downloadType, filesToCompress[t], zipOutputStream);
                    }
                } catch (IOException e) {
                    log.error("压缩文件生成失败：" + e.getMessage());
                    throw new BusinessException(ResponseEnum.FAILED_TO_GENERATE_COMPRESSED_FILE);
                }
                downloadType = "zip";
                fileName = "dzfp_" + DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
                bFile = FileStreamUtil.fileToBytes(zipFileName);
                // 删掉
                FileUtils.del(zipFileName);
            }
            FileUtils.downloadPdfFile(bFile, fileName + "." + downloadType);
        } catch (BusinessException e) {
            FileUtils.del(filePathAndName);
            throw e;
        } catch (Exception e) {
            FileUtils.del(filePathAndName);
            e.printStackTrace();
            throw e;
        }
    }

    private void genFile(String downloadType, VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails, List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems, String filePathAndName, String deptCode) {
        File file = new File(filePathAndName);
        if (!file.exists()) {
            String errorMsg = verifyLegality(vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems);
            if (StringUtil.isNotEmpty(errorMsg)) {
                throw new BusinessException(ResponseEnum.INVOICE_DOWNLOAD_EXCEPTION.getCode(), "下载发票校验未通过:" + errorMsg);
            }
            if ("xml".equals(downloadType)) {
                generationXml(vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems, filePathAndName, deptCode);
            }
            if ("pdf".equals(downloadType)) {
                generationPdf(vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems, filePathAndName, deptCode);
            }
            if ("ofd".equals(downloadType)) {
                generationOfd(vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems, filePathAndName, deptCode);
            }
        }
    }

    private String verifyLegality(VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails, List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems) {
        String errorMsg = "";
        // 专票购买方纳税人识别号不能为空。
        if ("01".equals(vmsFullOutInvoiceDetails.getFppz())) {
            if (StringUtil.isEmpty(vmsFullOutInvoiceDetails.getGmfnsrsbh())) {
                errorMsg = "专票购买方纳税人识别号不能为空";
            }
        }

        int mxxh = 1;
        for (VmsFullOutInvoiceItems vmsFullOutInvoiceItem : vmsFullOutInvoiceItems) {
            // 明细序号自然数递增校验。
            if (mxxh != vmsFullOutInvoiceItem.getMxxh()) {
                errorMsg = "明细序号自然数递增校验未通过";
                break;
            }
            mxxh++;
        }


        return errorMsg;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<String> uploadFphm(List<String> fphm) {
        // 1.查询所有发票信息
        List<VmsFullOutInvoiceDetails> invoiceList = list(new LambdaQueryWrapper<VmsFullOutInvoiceDetails>()
                .in(VmsFullOutInvoiceDetails::getFphm, fphm)
        );
        // 区分上传接口 和 查询接口 0:初始化 , 1:未上传 或者 上传失败 , 2:上传中
        String flag = "0";
        // 发票信息
        List<VmsFullOutInvoiceDetails> itemList = new ArrayList<>();
        // 可以准备上传的发票信息 (包含 未上传 和 上传失败)
        // 2.检查发票信息上传状态,将发票添加到 list 中
        for (VmsFullOutInvoiceDetails item : invoiceList) {
            // 发票上传状态;0：未上传 1：上传中 2：已上传 3：上传失败
            if (CommonEnum.INVOICE_UPLOAD_STATUS_2.getKey().equals(item.getSczt())) {
                throw new BusinessException(ResponseEnum.INVOICE_STATUS_ABNORMAL_01);
            }
            if (CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey().equals(item.getSczt())) {
                throw new BusinessException(ResponseEnum.INVOICE_STATUS_ABNORMAL_02);
            }
            // 未上传 进入这个分支
            if (CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey().equals(item.getSczt())) {
                // 区分上传接口 和 查询接口
                // flag为2 说明之前有上传中的发票 所以抛出异常, 不允许上传
                if ("2".equals(flag)) {
                    throw new BusinessException(ResponseEnum.INVOICE_UPLOAD_ERROR_02);
                }
                flag = "1";
            } else {
                // 上传中 进入这个分支
                // 区分上传接口 和 查询接口
                // 1 说明之前有 未上传和上传失败的发票 所以抛出异常, 不允许上传
                if ("1".equals(flag)) {
                    throw new BusinessException(ResponseEnum.INVOICE_UPLOAD_ERROR_02);
                }
                flag = "2";
            }
            itemList.add(item);
        }

        if ("1".equals(flag)) {
            // 如果 flag = 1 将发票主键id放入发票上传队列
            for (VmsFullOutInvoiceDetails invoiceDetail : itemList) {
                // 修改上传结果
                LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(VmsFullOutInvoiceDetails::getScjg, "等待定时任务上传中");
                updateWrapper.eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                this.update(updateWrapper);
                boolean queueFlag = uploadInvoiceVmsQueue.addMessageToQueue(invoiceDetail.getFoidid());
                if (!queueFlag) {
                    return Result.ERROR(ResponseEnum.REDIS_QUEUE_ERROR);
                }
            }
        } else if ("2".equals(flag)) {
            // 如果 flag = 2 将受理流水号放入查询上传结果队列
            Set<String> set = new HashSet<>();
            itemList.forEach(item -> set.add(item.getSllsh()));
            for (String sllsh : set) {
                String meaasge = sllsh + "-" + itemList.get(0).getQydjid() + "-" + "0";
                boolean queueFlag = queryUploadInvoiceVmsQueue.addMessageToQueue(meaasge);
                if (!queueFlag) {
                    return Result.ERROR(ResponseEnum.REDIS_QUEUE_ERROR);
                }
            }
            // 修改上传结果
            for (VmsFullOutInvoiceDetails invoiceDetail : itemList) {
                LambdaUpdateWrapper<VmsFullOutInvoiceDetails> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.set(VmsFullOutInvoiceDetails::getScjg, "等待定时任务查询上传结果中");
                updateWrapper.eq(VmsFullOutInvoiceDetails::getFoidid, invoiceDetail.getFoidid());
                this.update(updateWrapper);
            }
        }
        // 3.返回成功
        return Result.OK("操作成功");
    }

    @Override
    public boolean checkUploadFull(String deptCode) {
        LambdaQueryWrapper<VmsFullOutInvoiceDetails> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VmsFullOutInvoiceDetails::getQydjid, deptCode);
        queryWrapper.in(VmsFullOutInvoiceDetails::getSczt, CommonEnum.INVOICE_UPLOAD_STATUS_0.getKey(),
                CommonEnum.INVOICE_UPLOAD_STATUS_1.getKey(), CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey());
        // 发票上传时间与开票时间间隔应当小于48小时
        // 发票上传结果只能在发票上传后12小时内查询，如果超过12小时只能重新上传发票再获取上传结果
        LambdaQueryWrapper<VmsCreditLimit> query = new LambdaQueryWrapper<>();
        query.select(VmsCreditLimit::getSyqjq);
        query.eq(VmsCreditLimit::getDeptCode, deptCode);
        VmsCreditLimit vmsCreditLimit = creditLimitService.getOne(query);
        Date kprqDate;
        if (vmsCreditLimit != null) {
            kprqDate = vmsCreditLimit.getSyqjq();
        } else {
            kprqDate = DateUtil.offsetDay(new Date(), -30);
        }
        // 查询大于等于授信额度使用区间的数据
        String kprq = DateUtil.format(kprqDate, CommonConstant.DATE_FORMAT_14);
        queryWrapper.apply("KPRQ >= TO_DATE({0},'yyyy-mm-dd hh24:mi:ss')", kprq);
        int count = count(queryWrapper);
        return count == 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> rollBackInvoice(List<VmsFullOutInvoiceDTO> invoiceDTOList, TokenUser tokenUser) {
        String redisLockKey = String.format(RedisConstant.REDIS_SYED_YFM_LOCK_KEY, tokenUser.getDeptCode());
        RLock lock = redisService.getLock(redisLockKey);
        boolean success = redisService.tryLock(lock, 3, 500);
        if (!success) {
            log.info("尝试指定次数后均未获取到锁，返回系统繁忙");
            return Result.ERROR(ResponseEnum.REDIS_LOCK_NO_GET);
        }
        log.info("redisson上锁成功，key：{}", redisLockKey);

        try {
            List<VmsFullOutInvoiceDetails> invoiceList = new ArrayList<>();
            // 校验该批次的上传状态
            for (VmsFullOutInvoiceDTO dto : invoiceDTOList) {
                // 获取发票主信息
                LambdaQueryWrapper<VmsFullOutInvoiceDetails> invoiceQueryWrapper = new LambdaQueryWrapper<>();
                invoiceQueryWrapper.eq(VmsFullOutInvoiceDetails::getFoidid, dto.getFoidid());
                VmsFullOutInvoiceDetails invoice = this.getOne(invoiceQueryWrapper);
                // 只有上传失败的发票允许回滚
                if (!CommonEnum.INVOICE_UPLOAD_STATUS_3.getKey().equals(invoice.getSczt())) {
                    return Result.ERROR(ResponseEnum.ROLLBACK_SCZT_ERROR);
                }
                if (CommonEnum.DATA_SOURCE_99.getKey().equals(invoice.getSjly())) {
                    return Result.ERROR(ResponseEnum.ROLLBACK_SJLY_ERROR);
                }
                invoiceList.add(invoice);
            }
            // 进行回滚操作
            for (VmsFullOutInvoiceDetails invoice : invoiceList) {
                // 删除发票主信息和老系统发票主信息数据
                this.getBaseMapper().deleteById(invoice.getFoidid());
                nvatOutInvoiceService.deleteNvatOutInvoiceDetails(invoice.getOidid());

                // 获取发票明细信息
                LambdaQueryWrapper<VmsFullOutInvoiceItems> itemsQueryWrapper = new LambdaQueryWrapper<>();
                itemsQueryWrapper.eq(VmsFullOutInvoiceItems::getFoidid, invoice.getFoidid());
                List<VmsFullOutInvoiceItems> itemsList = fullOutInvoiceItemsService.list(itemsQueryWrapper);
                // 删除发票明细信息和老系统发票明细信息数据
                fullOutInvoiceItemsService.remove(itemsQueryWrapper);
                for (VmsFullOutInvoiceItems items : itemsList) {
                    nvatOutInvoiceService.deleteNvatOutInvoiceItems(items.getIviid());
                }

                // 删除发票扩展信息
                LambdaQueryWrapper<VmsFullOutInvoiceItemsExp> expQueryWrapper = new LambdaQueryWrapper<>();
                expQueryWrapper.eq(VmsFullOutInvoiceItemsExp::getFoidid, invoice.getFoidid());
                fullOutInvoiceItemsExpService.remove(expQueryWrapper);

                // 删除发票附加要素信息
                LambdaQueryWrapper<VmsFullOutInvoiceItemsAdd> addQueryWrapper = new LambdaQueryWrapper<>();
                addQueryWrapper.eq(VmsFullOutInvoiceItemsAdd::getFoidid, invoice.getFoidid());
                fullOutInvoiceItemsAddService.remove(addQueryWrapper);

                if (CommonEnum.CEZS_02.getKey().equals(invoice.getCezslxdm())) {
                    // 删除发票差额扣除信息
                    LambdaQueryWrapper<VmsFullOutInvoiceCekc> cekcQueryWrapper = new LambdaQueryWrapper<>();
                    cekcQueryWrapper.eq(VmsFullOutInvoiceCekc::getFoidid, invoice.getFoidid());
                    fullOutInvoiceCekcService.remove(cekcQueryWrapper);
                }

                if (StrUtil.equalsAny(invoice.getTdys(), TdysEnum.TDYS_05.getCode(),
                        TdysEnum.TDYS_06.getCode(), TdysEnum.TDYS_09.getCode())) {
                    // 查询特定业务信息
                    LambdaQueryWrapper<VmsFullOutInvoiceTdyw> tdywWrapper = new LambdaQueryWrapper<>();
                    tdywWrapper.eq(VmsFullOutInvoiceTdyw::getFoidid, invoice.getFoidid());
                    List<VmsFullOutInvoiceTdyw> invoiceTdywList = fullOutInvoiceTdywService.list(tdywWrapper);

                    // 删除特定业务信息
                    fullOutInvoiceTdywService.remove(tdywWrapper);

                    // 不动产销售还需要删除特定业务明细信息
                    if (TdysEnum.TDYS_05.getCode().equals(invoice.getTdys())) {
                        VmsFullOutInvoiceTdyw invoiceTdyw = invoiceTdywList.get(0);
                        if (CommonConstant.STR_Y.equals(invoiceTdyw.getDfgtgmbz())) {
                            LambdaQueryWrapper<VmsFullOutInvoiceTdywItem> tdywItemWrapper = new LambdaQueryWrapper<>();
                            tdywItemWrapper.eq(VmsFullOutInvoiceTdywItem::getTdywId, invoiceTdyw.getTdywId());
                            fullOutInvoiceTdywItemService.remove(tdywItemWrapper);
                        }
                    }
                }

                // 流水、官网开票还需要删除发票和流水关联关系表
                if (CommonEnum.DATA_SOURCE_0.getKey().equals(invoice.getSjly())
                        || CommonEnum.DATA_SOURCE_2.getKey().equals(invoice.getSjly())) {
                    // 查询发票和流水关联关系表
                    LambdaQueryWrapper<NvatRevmapinvoitems> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(NvatRevmapinvoitems::getOidid, invoice.getOidid());
                    List<NvatRevmapinvoitems> rdidList = nvatRevmapinvoitemsMapper.selectList(wrapper);
                    if (CollectionUtil.isNotEmpty(rdidList)) {
                        for (NvatRevmapinvoitems rdid : rdidList) {
                            // 获取流水的未开票金额
                            LambdaQueryWrapper<NvatTrandtadvaltaxsep> queryWrapper = new LambdaQueryWrapper<>();
                            queryWrapper.eq(NvatTrandtadvaltaxsep::getRdid, rdid.getRdid());
                            NvatTrandtadvaltaxsep one = vmsNvatTrandtadvaltaxsepMapper.selectOne(queryWrapper);
                            BigDecimal wkpje = ObjectUtil.isEmpty(one.getJyrmbje()) ? BigDecimal.ZERO : one.getJyrmbje();

                            // 修改流水的状态为未开票
                            LambdaUpdateWrapper<NvatTrandtadvaltaxsep> updateWrapper = new LambdaUpdateWrapper<>();
                            updateWrapper.set(NvatTrandtadvaltaxsep::getLszt, 1L);
                            updateWrapper.set(NvatTrandtadvaltaxsep::getWkpje, wkpje);
                            updateWrapper.eq(NvatTrandtadvaltaxsep::getRdid, rdid.getRdid());
                            vmsNvatTrandtadvaltaxsepMapper.update(null, updateWrapper);

                            // 负数流水处理
                            if (wkpje.compareTo(BigDecimal.ZERO) < 0) {
                                LambdaUpdateWrapper<NvatNegativestream> update = new LambdaUpdateWrapper<>();
                                update.set(NvatNegativestream::getClzt, CommonConstant.STR_0);
                                update.set(NvatNegativestream::getCllx, "");
                                update.set(NvatNegativestream::getCzr, "");
                                update.set(NvatNegativestream::getCzrq, "");
                                update.set(NvatNegativestream::getCzsm, "");
                                update.eq(NvatNegativestream::getRdid, rdid.getRdid());
                                nvatNegativestreamService.update(update);
                            }
                        }
                        // 删除发票和流水关联关系
                        nvatRevmapinvoitemsMapper.delete(wrapper);
                    }
                }

                log.info("回滚的发票号码：{}，授信额度：{}", invoice.getFphm(), invoice.getHjje());

                // 授信额度更新
                VmsCreditLimit sxed = creditLimitService.getSxedByDeptCode(tokenUser.getDeptCode());
                if (sxed == null) {
                    throw new BusinessException(ResponseEnum.SXED_NOT_FOUND_ERROR);
                }

                // 红票处理
                if (CommonEnum.INVOICE_RED.getKey().equals(invoice.getLzfpbz())) {
                    // 红票删除老系统红蓝票关联关系表
                    // todo 删除的字段是否为索引字段 建议ooidid设为索引
                    LambdaQueryWrapper<NvatOutInvomapSelf> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(NvatOutInvomapSelf::getNoidid, invoice.getOidid());
                    nvatOutInvomapselfMapper.delete(wrapper);

                    // 查询原蓝票信息
                    LambdaQueryWrapper<NvatOutInvoiceDetails> query = new LambdaQueryWrapper<>();
                    query.eq(NvatOutInvoiceDetails::getFphm, invoice.getDylzfphm());
                    NvatOutInvoiceDetails nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(query);
                    if (nvatOutInvoiceDetails == null) {
                        // 如果没查到，判断红冲的是税控发票，对应蓝字发票号码的填写规则为税控发票的发票代码+发票号码
                        if (invoice.getDylzfphm() != null && invoice.getDylzfphm().length() == 20) {
                            LambdaQueryWrapper<NvatOutInvoiceDetails> query2 = new LambdaQueryWrapper<>();
                            query2.eq(NvatOutInvoiceDetails::getFpdm, invoice.getDylzfphm().substring(0, 12));
                            query2.eq(NvatOutInvoiceDetails::getFphm, invoice.getDylzfphm().substring(12));
                            nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(query2);
                        } else if (invoice.getDylzfphm() != null && invoice.getDylzfphm().length() == 18) {
                            // 此处兼容老增值税发票，发票代码为10位
                            LambdaQueryWrapper<NvatOutInvoiceDetails> query2 = new LambdaQueryWrapper<>();
                            query2.eq(NvatOutInvoiceDetails::getFpdm, invoice.getDylzfphm().substring(0, 10));
                            query2.eq(NvatOutInvoiceDetails::getFphm, invoice.getDylzfphm().substring(10));
                            nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(query2);
                        } else {
                            throw new BusinessException(ResponseEnum.DYLZFPHM_ERROR);
                        }
                    }
                    if (nvatOutInvoiceDetails == null) {
                        throw new BusinessException(ResponseEnum.HZQRD_NO_INVOICE_ERROR);
                    }
                    // 蓝票为当月开具，则减少本月授信额度
                    String blueTime = DateUtil.format(nvatOutInvoiceDetails.getKprq(), CommonConstant.DATE_FORMAT_6);
                    String redTime = DateUtil.format(invoice.getKprq(), CommonConstant.DATE_FORMAT_6);
                    if (redTime.equals(blueTime)) {
                        // 授信额度更新
                        Boolean update2 = creditLimitService.updateSxed(CommonConstant.SXED_REDUCE, SxedUpdateEnum.SXED_RED_ROLLBACK,
                                invoice.getHjje().abs(), sxed, tokenUser);
                        if (!update2) {
                            throw new BusinessException(ResponseEnum.SQL_ROLLBACK_ERROR);
                        }
                    }

                    // 防止循环依赖
                    VmsHzqrdApplyService vmsHzqrdApplyService = SpringUtil.getBean(VmsHzqrdApplyService.class);
                    // 计算原蓝票已红冲金额税额，第一步已删除老系统红蓝票关联关系表
                    Map<Long, Map<String, BigDecimal>> hasBeenRed = vmsHzqrdApplyService.calculateHasBeenRed(nvatOutInvoiceDetails.getFpdm(), nvatOutInvoiceDetails.getFphm());
                    // 税控蓝票状态、数电蓝票状态
                    String skLpzt, sdLpzt;
                    if (hasBeenRed.isEmpty()) {
                        // 已红冲金额税额为空，原蓝票状态为正常
                        skLpzt = CommonEnum.SK_INVOICE_STATUS_1.getKey();
                        sdLpzt = CommonEnum.INVOICE_STATUS_0.getKey();
                    } else {
                        // 已红冲金额税额为不为空，原蓝票状态为部分红冲
                        skLpzt = CommonEnum.SK_INVOICE_STATUS_3.getKey();
                        sdLpzt = CommonEnum.INVOICE_STATUS_7.getKey();
                    }

                    // 更新原蓝票的发票状态（税控表）
                    nvatOutInvoiceDetailsMapper.updateInvoiceFpzt(Integer.parseInt(skLpzt), null,
                            null, nvatOutInvoiceDetails.getOidid());

                    // 更新原蓝票的发票状态（数电表）
                    LambdaQueryWrapper<VmsFullOutInvoiceDetails> query2 = new LambdaQueryWrapper<>();
                    query2.eq(VmsFullOutInvoiceDetails::getFphm, invoice.getDylzfphm());
                    VmsFullOutInvoiceDetails vmsInvoice = this.getOne(query2);
                    if (vmsInvoice != null) {
                        this.baseMapper.updateInvoiceFpzt(sdLpzt, null, null, vmsInvoice.getFoidid());
                    }

                } else {
                    Boolean update = creditLimitService.updateSxed(CommonConstant.SXED_ADD, SxedUpdateEnum.SXED_BLUE_ROLLBACK,
                            invoice.getHjje(), sxed, tokenUser);
                    if (!update) {
                        throw new BusinessException(ResponseEnum.SQL_ROLLBACK_ERROR);
                    }
                }

                // 预赋码更新
                Result<Object> result = fullYfmMessageService.rollBackYfm(invoice.getFphm(), tokenUser);
                if (!ResponseEnum.SUCCESS.getCode().equals(result.getCode())) {
                    throw new BusinessException(result.getCode(), result.getMessage());
                }
            }

            return Result.OK();
        } catch (BusinessException e) {
            log.error("回滚已开发票出现业务异常，code：{}，msg：{}", e.getCode(), e.getMsg());
            throw new BusinessException(e.getCode(), e.getMsg());
        } catch (Exception e) {
            log.error("回滚已开发票出现未知异常" + e);
            throw new BusinessException(ResponseEnum.ERROR);
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                log.info("redisson释放锁成功，key为:{}", redisLockKey);
                lock.unlock();
            } else {
                log.info("redisson释放锁失败，key为:{}", redisLockKey);
            }
        }
    }

    @Override
    public Result<InvoiceDetailVO> detail(String fphm) {
        InvoiceDetailVO vo = new InvoiceDetailVO();
        VmsFullOutInvoiceDetails one = getOne(new LambdaQueryWrapper<VmsFullOutInvoiceDetails>()
                .eq(VmsFullOutInvoiceDetails::getFphm, fphm)
        );
        BeanUtils.copyBeanProp(vo, one);
        vo.setJshjxx(one.getJshj());
        vo.setJshjdx(MoneyUtils.toChinese(StringUtil.toString(vo.getJshjxx())));
        // 发票明细
        List<InvoiceDetailItemVO> items = fullOutInvoiceItemsService.queryInvoiceDetails(one.getFoidid()).stream().map(item -> {
            InvoiceDetailItemVO itemVO = new InvoiceDetailItemVO();
            BeanUtils.copyBeanProp(itemVO, item);
            itemVO.setDj(item.getDj());
            return itemVO;
        }).collect(Collectors.toList());
        vo.setItems(items);

        // 标题
        if (CommonEnum.INVOICE_TYPE_01.getKey().equals(one.getFppz())) {
            vo.setTitle("电子发票（增值税专用发票）");
        } else {
            vo.setTitle("电子发票（普通发票）");
        }
        // 差额征税
        if (StringUtil.isNotEmpty(one.getCezslxdm())) {
            if (CommonEnum.CEZS_01.getKey().equals(one.getCezslxdm())) {
                vo.setCezs("差额征税-全额开票");
            } else {
                vo.setCezs("差额征税-差额开票");
            }
        }

        String tdys = one.getTdys();
        if (StringUtil.isNotEmpty(tdys)) {
            String defBizDictValue = dictService.getDefBizDictValue(DictConstant.VMS_TDYSBQGL, tdys);
            vo.setFptdys(defBizDictValue);
        }

        return Result.OK(vo);
    }

    @Override
    public void invoiceDownload(String text, String downloadType) {
        byte[] bytes = sm4Properties.getKey().getBytes();
        SymmetricCrypto sm4 = new SymmetricCrypto("SM4/ECB/PKCS5Padding", bytes);
        String[] fphm = sm4.decryptStr(text).split("&");
        VmsFullOutInvoiceDownloadDTO dto = new VmsFullOutInvoiceDownloadDTO();
        dto.setFphms(fphm);
        dto.setDownloadType(downloadType);
        fileDownload(dto);
    }

    @Override
    public HashMap<String, String> fileDownload(List<String> fphms, String type) {
        // 文件名称
        String fileName = "";
        int fileSize = fphms.size();
        // 文件根地址
        String fileAddress = vmsProperties.fullPath();
        // 文件地址名称
        String filePathAndName = "";
        // 报错机构集合
        HashMap<String, String> errorMap = new HashMap<>();
        // 压缩
        try {
            for (int i = 0; i < fileSize; i++) {
                String fphm = fphms.get(i);
                fileName = "dzfp_" + fphm + "_" + DateUtils.formatDate(new Date(), "yyyyMMddHHmmss");
                VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails = this.queryInvoiceInfo(fphm);
                // 校验当前机构 版式文件生成 是否启用
                boolean flag = bswjRedisService.getBswjscztSwitch(vmsFullOutInvoiceDetails.getQydjid());
                if (!flag) {
                    errorMap.put(vmsFullOutInvoiceDetails.getQydjid(), fullBswjManagerService.getOneByWhjg(vmsFullOutInvoiceDetails.getQydjid()).getNsztName());
                    return errorMap;
                } else {
                    List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems = this.queryInvoiceDetails(vmsFullOutInvoiceDetails.getFoidid());

                    String kpnssbh = vmsFullOutInvoiceDetails.getXsfnsrsbh();
                    // 目录 税号 年 月日
                    filePathAndName = fileAddress + kpnssbh + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "yyyy") + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "MMdd") + File.separator + fphm + "." + type;
                    File file = new File(fileAddress + kpnssbh + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "yyyy") + File.separator + DateUtil.format(vmsFullOutInvoiceDetails.getKprq(), "MMdd"));
                    if (!file.exists()) {
                        file.mkdirs();
                    }
                    File file2 = new File(filePathAndName);
                    if (!file2.exists()) {
                        genFile(type, vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems, filePathAndName, vmsFullOutInvoiceDetails.getQydjid());
                    }
                }
            }
        } catch (Exception e) {
            FileUtils.del(filePathAndName);
            e.printStackTrace();
            throw e;
        }
        return errorMap;
    }

    private VmsFullOutInvoiceDetails queryInvoiceInfo(String fphm) {
        LambdaQueryWrapper<VmsFullOutInvoiceDetails> wrapper = new LambdaQueryWrapper<VmsFullOutInvoiceDetails>().eq(VmsFullOutInvoiceDetails::getFphm, fphm);
        return this.baseMapper.selectOne(wrapper);
    }


    /**
     * 查询发票明细
     *
     * @param mainId
     * @return
     */
    public List<VmsFullOutInvoiceItems> queryInvoiceDetails(Long mainId) {
        return fullOutInvoiceItemsService.queryInvoiceDetails(mainId);
    }

    /**
     * PDF
     *
     * @param vmsFullOutInvoiceDetails
     * @param vmsFullOutInvoiceItems
     * @param outPath
     * @param deptCode
     */
    public void generationPdf(VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails, List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems, String outPath, String deptCode) {
        String pdfStr = outPath;
        String ofdStr = outPath.replace(".pdf", ".ofd");
        File file = new File(ofdStr);
        if (!file.exists()) {
            generationOfd(vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems, ofdStr, deptCode);
        }
        Path ofdPath = Paths.get(ofdStr);
        Path pdfPath = Paths.get(pdfStr);
        try (OFDExporter exporter = new PDFExporterIText(ofdPath, pdfPath)) {
            exporter.export();
        } catch (IOException e) {
            log.info("OFD转换PDF失败!");
            throw new BusinessException(ResponseEnum.INVOICE_DOWNLOAD_FAIL_01);
        }
    }

    public void generationOfd(VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails, List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems, String ofdFileOutputPath, String deptCode) {
        try {
            OriginalInvoice originalInvoice = transformOriginalInvoice(vmsFullOutInvoiceDetails, vmsFullOutInvoiceItems);
            GenerateInvoiceService genInvoice = OfdInvoiceUtils.getGenInvoice(originalInvoice.getTdys());
            if (ObjectUtil.isEmpty(genInvoice)) {
                throw new BusinessException(ResponseEnum.INVOICE_DOWNLOAD_FAIL_02);
            }
            genInvoice.generateInvoice(originalInvoice, ofdFileOutputPath);
        } catch (BusinessException e) {
            FileUtils.del(ofdFileOutputPath);
            throw e;
        } catch (IOException e) {
            FileUtils.del(ofdFileOutputPath);
            e.printStackTrace();
        }
    }

    private void generationXml(VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails, List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems, String filePathAndName, String deptCode) {
        // 纳税人基本信息
        VmsEnterpriseInfo vmsEnterpriseInfo = enterpriseInfoService.getInfoByRedis(deptCode);
        // 发票非必填信息
        VmsFullOutInvoiceItemsExp invoiceExp = fullOutInvoiceItemsExpService.getInvoiceExpInfoByFoidid(vmsFullOutInvoiceDetails.getFoidid());
        // 版式文件
        VmsFullBswjManager data = fullBswjManagerService.getOneByWhjg(deptCode);


        XMLEntity xmlEntity = new XMLEntity();
        // 根节点
        EInvoice eInvoice = new EInvoice();
        // 头部信息
        Header header = new Header();
        // 电子发票识别码
        header.setEIid(vmsFullOutInvoiceDetails.getFphm());
        // 电子发票标识
        header.setEInvoiceTag("SWEI" + data.getQydm().substring(0, 4));
        // 版本 固定值 0.32
        header.setVersion("0.32");

        // 固定标签
        InherentLabel inherentLabel = new InherentLabel();

        // 开票类型
        InIssuType inIssuType = new InIssuType();
        // 0 是蓝字 1 是红字
        // Y 是蓝字 N 是红字
        // 是否蓝字发票
        inIssuType.setLabelName("是否蓝字发票标志");
        if (LzfpbzEnum.BULE.getKey().equals(vmsFullOutInvoiceDetails.getLzfpbz())) {
            // 蓝字发票
            inIssuType.setLabelCode(InIssuTypeEnum._Y.getKey());
        } else {
            // 红字
            inIssuType.setLabelCode(InIssuTypeEnum._N.getKey());
        }
        // 将 开票类型 填进 固定标签
        inherentLabel.setInIssuType(inIssuType);


        // 发票票种
        EInvoiceType eInvoiceType = new EInvoiceType();
        eInvoiceType.setLabelCode(EInvoiceTypeEnum._01.getKey());
        eInvoiceType.setLabelName(EInvoiceTypeEnum._01.getValue());
        // 将 发票票种 填进 固定标签
        inherentLabel.setEInvoiceType(eInvoiceType);


        // 票种类 发票票种字段
        GeneralOrSpecialVAT generalOrSpecialVAT = new GeneralOrSpecialVAT();
        String fppz = vmsFullOutInvoiceDetails.getFppz();
        // 数电专 对应 增值税专用发票
        // 数电普 对应 普通发票
        generalOrSpecialVAT.setLabelCode(fppz);
        String fppzName = GeneralOrSpecialEnum._01.getKey().equals(fppz) ? GeneralOrSpecialEnum._01.getValue() : GeneralOrSpecialEnum._02.getValue();
        generalOrSpecialVAT.setLabelName(fppzName);
        inherentLabel.setGeneralOrSpecialVAT(generalOrSpecialVAT);

        // 纳税人类型
        TaxpayerType taxpayerType = new TaxpayerType();
        taxpayerType.setLabelCode(vmsEnterpriseInfo.getNsrlx());
        taxpayerType.setLabelName(NsrlxEnum.getValueByKey(vmsEnterpriseInfo.getNsrlx()));
        inherentLabel.setTaxpayerType(taxpayerType);
        // 将 固定标签 添加到 头部信息 中
        header.setInherentLabel(inherentLabel);

        // 特定征税方式标签
        // 固定标签
        UndefinedLabel undefinedLabel = new UndefinedLabel();
        List<Label> labels = new ArrayList<>();

        // 企业行业性质类标签
        String qyhyxzdm = vmsEnterpriseInfo.getQyhyxzdm();
        if (StringUtil.isNotEmpty(qyhyxzdm)) {
            Label qyhyxzlbqLabel = new Label();
            qyhyxzdm = qyhyxzdm.replace("、", ",");
            String[] qyhyxzdmTmp = qyhyxzdm.split(",");
            int length = qyhyxzdmTmp.length;
            String[] qyhyxznameTmp = new String[length];
            for (int i = 0; i < qyhyxzdmTmp.length; i++) {
                String qyhyxzdmStr = qyhyxzdmTmp[i];
                qyhyxznameTmp[i] = dictService.getDefBizDictValue(DictConstant.VMS_QYHYXZDM, qyhyxzdmStr);
            }
            String qyhyxzname = ArrayUtil.join(qyhyxznameTmp, ",");
            qyhyxzlbqLabel.setLabelType("企业行业性质类标签");
            qyhyxzlbqLabel.setLabelCode(qyhyxzdm);
            qyhyxzlbqLabel.setLabelName(qyhyxzname);
            labels.add(qyhyxzlbqLabel);
        }

        // 发票开具方式标签
        Label fpkjfsLabel = new Label();
        fpkjfsLabel.setLabelType("发票开具方式标签");
        fpkjfsLabel.setLabelCode("6");
        fpkjfsLabel.setLabelName("离线开票");
        labels.add(fpkjfsLabel);

        // 消费税纳税人标签
        String xfsnsrlxdm = vmsEnterpriseInfo.getXfsnsrlxdm();
        if (StringUtil.isNotEmpty(xfsnsrlxdm)) {
            Label xfsnsrLabel = new Label();
            xfsnsrlxdm = xfsnsrlxdm.replace("、", ",");
            String[] xfsnsrlxdmTmp = xfsnsrlxdm.split(",");
            int length = xfsnsrlxdmTmp.length;
            String[] xfsnsrlxnameTmp = new String[length];
            for (int i = 0; i < xfsnsrlxdmTmp.length; i++) {
                String qyhyxzdmStr = xfsnsrlxdmTmp[i];
                xfsnsrlxnameTmp[i] = dictService.getDefBizDictValue(DictConstant.VMS_QYHYXZDM, qyhyxzdmStr);
            }
            String xfsnsrlxname = ArrayUtil.join(xfsnsrlxnameTmp, ",");
            xfsnsrLabel.setLabelType("消费税纳税人标签");
            xfsnsrLabel.setLabelCode(xfsnsrlxdm);
            xfsnsrLabel.setLabelName(xfsnsrlxname);
            labels.add(xfsnsrLabel);
        }
        // 出口企业分类管理标签
        String ckqyfldm = vmsEnterpriseInfo.getCkqyfldm();
        if (StringUtil.isNotEmpty(ckqyfldm) && !CommonConstant.STR_00.equals(ckqyfldm)) {
            Label ckqyflLabel = new Label();
            String ckqyflname = dictService.getDefBizDictValue(DictConstant.VMS_CKQYFL, ckqyfldm);
            ckqyflLabel.setLabelType("出口企业分类管理标签");
            ckqyflLabel.setLabelCode(ckqyfldm);
            ckqyflLabel.setLabelName(ckqyflname);
            labels.add(ckqyflLabel);
        }

        // 差额征税标签
        if (StringUtil.isNotEmpty(vmsFullOutInvoiceDetails.getCezslxdm())) {
            Label cezsLabel = new Label();
            String cezslxdm = vmsFullOutInvoiceDetails.getCezslxdm();
            String cezslxname = dictService.getDefBizDictValue(DictConstant.VMS_CEZS, cezslxdm);
            cezsLabel.setLabelType("差额征税标签");
            cezsLabel.setLabelCode(cezslxdm);
            cezsLabel.setLabelName(cezslxname);
            labels.add(cezsLabel);
        }
        // 纳税人信用等级
        VmsEnterpriseInfoRiskDto vmsEnterpriseInfoRiskDto = new VmsEnterpriseInfoRiskDto();
        vmsEnterpriseInfoRiskDto.setDeptCode(deptCode);
        Result<VmsEnterpriseInfoRiskVo> vmsEnterpriseInfoRiskVoResult = vmsEnterpriseInfoRiskService.queryVmsEnterpriseInfoRisk(vmsEnterpriseInfoRiskDto);
        VmsEnterpriseInfoRiskVo vo = vmsEnterpriseInfoRiskVoResult.getData();
        if (null != vo && 0 != vo.getId()) {
            if (StringUtil.isNotEmpty(vo.getNsrxydj())) {
                Label nsrxydjLabel = new Label();
                String nsrxydj = vo.getNsrxydj();
                String nsrxydjname = nsrxydj + "级";
                nsrxydjLabel.setLabelType("纳税人信用等级标签");
                nsrxydjLabel.setLabelCode(nsrxydj);
                nsrxydjLabel.setLabelName(nsrxydjname);
                labels.add(nsrxydjLabel);
            }
        }

        undefinedLabel.setLabel(labels);

        // 将 其他标签 添加到 头部信息 中
        header.setUndefinedLabel(undefinedLabel);
        // 将头部信息添加到根标签中
        eInvoice.setHeader(header);


        // 票面信息
        EInvoiceData eInvoiceData = new EInvoiceData();
        // 销售方人员信息
        SellerInformation sellerInformation = new SellerInformation();
        sellerInformation.setSellerIdNum(vmsFullOutInvoiceDetails.getXsfnsrsbh());
        sellerInformation.setSellerName(vmsFullOutInvoiceDetails.getXsfmc());
        if (ObjectUtil.isNotEmpty(invoiceExp)) {
            sellerInformation.setSellerAddr(invoiceExp.getXsfdz());
            sellerInformation.setSellerTelNum(invoiceExp.getXsfdh());
            sellerInformation.setSellerBankName(invoiceExp.getXsfkhh());
            sellerInformation.setSellerBankAccNum(invoiceExp.getXsfzh());
        }
        eInvoiceData.setSellerInformation(sellerInformation);


        BuyerInformation buyerInformation = new BuyerInformation();
        buyerInformation.setBuyerIdNum(vmsFullOutInvoiceDetails.getGmfnsrsbh());
        buyerInformation.setBuyerName(vmsFullOutInvoiceDetails.getGmfmc());
        if (ObjectUtil.isNotEmpty(invoiceExp)) {
            buyerInformation.setBuyerAddr(invoiceExp.getGmfdz());
            buyerInformation.setBuyerTelNum(invoiceExp.getGmfdh());
            buyerInformation.setBuyerBankName(invoiceExp.getGmfkhh());
            buyerInformation.setBuyerBankAccNum(invoiceExp.getGmfzh());
            buyerInformation.setBuyerHandlingName(invoiceExp.getGmfjbr());
        }
        eInvoiceData.setBuyerInformation(buyerInformation);

        // 票面基本信息
        BasicInformation basicInformation = new BasicInformation();
        basicInformation.setTotalAmWithoutTax(StringUtil.toString(vmsFullOutInvoiceDetails.getHjje()));
        basicInformation.setTotalTaxAm(StringUtil.toString(vmsFullOutInvoiceDetails.getHjse()));
        basicInformation.setTotalTaxIncludedAmount(StringUtil.toString(vmsFullOutInvoiceDetails.getJshj()));
        basicInformation.setTotalTaxIncludedAmountInChinese(MoneyUtils.toChinese(StringUtil.toString(vmsFullOutInvoiceDetails.getJshj())));
        basicInformation.setDrawer(vmsFullOutInvoiceDetails.getKpr());
        basicInformation.setRequestTime(DateUtils.formatDate(vmsFullOutInvoiceDetails.getKprq(), CommonConstant.DATE_FORMAT_14));
        eInvoiceData.setBasicInformation(basicInformation);

        // 票面明细信息
        if (!vmsFullOutInvoiceItems.isEmpty()) {
            List<IssuItemInformation> collect = vmsFullOutInvoiceItems.stream()
                    .map(item -> {
                        TdzsBqEnum tdzsBq = TdzsBqEnum.getTdzsBq(YhzcbsEnum.getYhzcbsEnumByKey(item.getYhzcbs()),
                                item.getSlv(), vmsFullOutInvoiceDetails.getCezslxdm());
                        if (tdzsBq != null) {
                            Label cezsLabel = new Label();
                            cezsLabel.setLabelType("特定征税方式标签");
                            cezsLabel.setLabelCode(tdzsBq.getKey());
                            cezsLabel.setLabelName(tdzsBq.getValue());
                            labels.add(cezsLabel);
                        }
                        IssuItemInformation issuItemInformation = new IssuItemInformation();
                        issuItemInformation.setItemName(item.getXmmc());
                        issuItemInformation.setSpecMod(item.getGgxh());
                        issuItemInformation.setMeaUnits(item.getDw());
                        issuItemInformation.setQuantity(item.getSl());
                        issuItemInformation.setUnPrice(item.getDj());
                        issuItemInformation.setAmount(StringUtil.toString(item.getJe()));
                        issuItemInformation.setTaxRate(StringUtil.toString(item.getSlv()));
                        issuItemInformation.setComTaxAm(StringUtil.toString(item.getSe()));
                        issuItemInformation.setTotaltaxIncludedAmount(StringUtil.toString((item.getJe().add(item.getSe()))));
                        issuItemInformation.setTaxClassificationCode(item.getSphfwssflhbbm());
                        return issuItemInformation;
                    }).collect(Collectors.toList());
            eInvoiceData.setIssuItemInformation(collect);
        }

        // 特定业务信息
        SpecificInformation specificInformation = new SpecificInformation();
        List<VmsFullOutInvoiceTdyw> infoByFoidid = new ArrayList<>();
        if (StringUtils.isNotBlank(vmsFullOutInvoiceDetails.getTdys())) {
            String tdys = vmsFullOutInvoiceDetails.getTdys();
            // 获取特定业务
            infoByFoidid = fullOutInvoiceTdywService.getInfoByFoidid(vmsFullOutInvoiceDetails.getFoidid());
            if (!infoByFoidid.isEmpty()) {
                VmsFullOutInvoiceTdyw tdyw = infoByFoidid.get(0);
                String ksbz = CommonConstant.STR_Y.equals(tdyw.getKdsbz()) ? "是" : "否";
                // 不动产销售服务
                if (TdysEnum.TDYS_05.getCode().equals(tdys)) {
                    RealEstateSales realEstateSales = new RealEstateSales();
                    realEstateSales.setRealEstateWarrantNumber(tdyw.getCqzsbh());
                    realEstateSales.setRealEstateAddress(tdyw.getBdczldzS() + tdyw.getBdczldzS1() + tdyw.getBdczldzXxdz());
                    realEstateSales.setRealEstateUnitNumber(tdyw.getBdcdwdm());
                    realEstateSales.setActualTransactionAmountIncludingTax(StringUtil.toString((tdyw.getSjcjhsje())));
                    realEstateSales.setLandValueAddedTaxProjectNumber(tdyw.getTdzzsxmbh());
                    realEstateSales.setCrossRegionIdentifier(ksbz);
                    realEstateSales.setApprovedTaxPrice(StringUtil.toString((tdyw.getHdjsjg())));
                    specificInformation.setRealEstateSales(realEstateSales);
                }
                // 不动产租赁
                if (TdysEnum.TDYS_06.getCode().equals(tdys)) {
                    RealEstateLease realEstateLease = new RealEstateLease();
                    realEstateLease.setRealEstateWarrantNumber(tdyw.getCqzsbh());
                    realEstateLease.setRealEstateAddress(tdyw.getBdczldzS() + tdyw.getBdczldzS1() + tdyw.getBdczldzXxdz());
                    realEstateLease.setTheLeaseTermBeginsAndEnds(tdyw.getZlqqz());
                    realEstateLease.setCrossRegionIdentifier(ksbz);
                    specificInformation.setRealEstateLease(realEstateLease);
                }
                // 旅客运输
                if (TdysEnum.TDYS_09.getCode().equals(tdys)) {
                    ArrayList<PassengerTransportation> passengerTransportations = new ArrayList<>();
                    for (VmsFullOutInvoiceTdyw tdyw1 : infoByFoidid) {
                        PassengerTransportation passengerTransportation = new PassengerTransportation();
                        passengerTransportation.setTraveler(tdyw1.getCxr());
                        passengerTransportation.setTravelDate(tdyw1.getChuxrq());
                        passengerTransportation.setDeparture(tdyw1.getCfd());
                        passengerTransportation.setDestination(tdyw1.getDdd());
                        passengerTransportation.setGrade(tdyw1.getZwdj());
                        passengerTransportation.setVehicletype(tdyw1.getJtgjlxdm());
                        passengerTransportation.setTypeOfPassengerDocument(tdyw1.getCxrzjlxdm());
                        passengerTransportation.setValidIDNumber(tdyw1.getSfzjhm());
                        passengerTransportations.add(passengerTransportation);
                    }
                    specificInformation.setPassengerTransportation(passengerTransportations);
                }
            }
        }


        // 是否差额开票
        if (StringUtil.isNotEmpty(vmsFullOutInvoiceDetails.getCezslxdm())) {
            DifferentialTaxation differentialTaxation = new DifferentialTaxation();
            BigDecimal totalDeduction = vmsFullOutInvoiceItems.stream()
                    // 过滤出kce不为null的项
                    .map(VmsFullOutInvoiceItems::getKce)
                    // 将所有kce值相加得到总和
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            differentialTaxation.setDeduction(StringUtil.toString(totalDeduction));
            differentialTaxation.setSalesIncludingTax(StringUtil.toString(vmsFullOutInvoiceDetails.getJshj()));
            specificInformation.setDifferentialTaxation(differentialTaxation);
        }


        String lzfpbz = vmsFullOutInvoiceDetails.getLzfpbz();
        if (LzfpbzEnum.RED.getKey().equals(lzfpbz) && KpztEnum._2.getKey().equals(vmsFullOutInvoiceDetails.getKpzt())) {
            RedEInvoice redEInvoice = new RedEInvoice();
            // 如果开票成功 就会有
            // 被红冲蓝字数电发票号码
            redEInvoice.setOriginalInvoiceCode(vmsFullOutInvoiceDetails.getDylzfphm());
            // 红字发票信息确认单编号
            redEInvoice.setCreditNoteNumber(vmsFullOutInvoiceDetails.getHzqrxxdbh());
            specificInformation.setRedEInvoice(redEInvoice);
        }

        eInvoiceData.setSpecificInformation(specificInformation);

        // 附加信息
        AdditionalInformation additionalInformation = new AdditionalInformation();
        additionalInformation.setRemark(vmsFullOutInvoiceDetails.getBz());
        eInvoiceData.setAdditionalInformation(additionalInformation);

        // 不动产销售 共同购买方
        if (StringUtils.isNotEmpty(vmsFullOutInvoiceDetails.getTdys()) && CommonEnum.TDYS_05.getKey().equals(vmsFullOutInvoiceDetails.getTdys())) {
            if (ObjectUtil.isNotEmpty(infoByFoidid)) {
                // 取出 TDYW_ID
                VmsFullOutInvoiceTdyw vmsFullOutInvoiceTdyw = infoByFoidid.get(0);
                Long tdywId = vmsFullOutInvoiceTdyw.getTdywId();
                // 查找是否有 共同购买人
                List<VmsFullOutInvoiceTdywItem> invoiceTdywItemByTdywId = fullOutInvoiceTdywItemService.getInvoiceTdywItemByTdywId(tdywId);
                if (ObjectUtil.isNotEmpty(invoiceTdywItemByTdywId)) {
                    ArrayList<Additional> additionals = new ArrayList<>();
                    invoiceTdywItemByTdywId.forEach(item -> {
                        Additional additional = new Additional();
                        if (StringUtil.isNotEmpty(item.getGtgmf())) {
                            additional.setInformation(item.getGtgmf());
                        }
                        if (StringUtil.isNotEmpty(item.getZjlx())) {
                            additional.setInformationType(ZjlxEnum.getNameByCode(item.getZjlx()));
                        }
                        if (StringUtil.isNotEmpty(item.getZjhm())) {
                            additional.setInformationValue(item.getZjhm());
                        }
                        additionals.add(additional);
                    });
                    eInvoiceData.setAdditional(additionals);
                }
            }

        }

        eInvoice.setEInvoiceData(eInvoiceData);


        // todo 认证方式 没有认证方式可以为空
        SellerAuthentication sellerAuthentication = new SellerAuthentication();
        sellerAuthentication.setAuthenticationMethods("01");
        eInvoice.setSellerAuthentication(sellerAuthentication);

        // 税务监制信息
        TaxSupervisionInfo taxSupervisionInfo = new TaxSupervisionInfo();
        taxSupervisionInfo.setInvoiceNumber(vmsFullOutInvoiceDetails.getFphm());
        taxSupervisionInfo.setIssueTime(DateUtils.formatDate(vmsFullOutInvoiceDetails.getKprq(), CommonConstant.DATE_FORMAT_8));

        // 监制税务代码
        taxSupervisionInfo.setTaxBureauCode(data.getQydm());
        // 监制税务名称
        taxSupervisionInfo.setTaxBureauName("国家税务总局" + data.getQymc());
        eInvoice.setTaxSupervisionInfo(taxSupervisionInfo);


        // 平台编号
        eInvoice.setPtbh(vmsFullOutInvoiceDetails.getPtbh());
        xmlEntity.setEInvoice(eInvoice);
        XmlInvoiceUtils.genEInvoice(xmlEntity, filePathAndName);
    }

    private static void addToZipFile(String fileName, String fileAbsolutePath, ZipOutputStream zipOutputStream) throws IOException {
        // 创建ZipEntry对象并设置文件名
        ZipEntry entry = new ZipEntry(fileName);
        zipOutputStream.putNextEntry(entry);
        // 写入文件内容到Zip文件
        try (FileInputStream fileInputStream = new FileInputStream(fileAbsolutePath)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                zipOutputStream.write(buffer, 0, bytesRead);
            }
        }
        // 完成当前文件的压缩
        zipOutputStream.closeEntry();
    }

    private OriginalInvoice transformOriginalInvoice(VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails, List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItems) {
        OriginalInvoice originalInvoice = new OriginalInvoice();
        originalInvoice.setInvoiceNo(vmsFullOutInvoiceDetails.getFphm());
        originalInvoice.setBuyerName(vmsFullOutInvoiceDetails.getGmfmc());
        originalInvoice.setBuyerTaxID(vmsFullOutInvoiceDetails.getGmfnsrsbh());
        originalInvoice.setSellerName(vmsFullOutInvoiceDetails.getXsfmc());
        originalInvoice.setSellerTaxID(vmsFullOutInvoiceDetails.getXsfnsrsbh());
        originalInvoice.setTaxInclusiveTotalAmount(StringUtil.toString(vmsFullOutInvoiceDetails.getJshj().setScale(2, RoundingMode.HALF_UP)));
        originalInvoice.setTaxTotalAmount(StringUtil.toString(vmsFullOutInvoiceDetails.getHjse()));
        originalInvoice.setTaxExclusiveTotalAmount(StringUtil.toString(vmsFullOutInvoiceDetails.getHjje()));
        originalInvoice.setNote(vmsFullOutInvoiceDetails.getBz());
        originalInvoice.setInvoiceClerk(vmsFullOutInvoiceDetails.getKpr());
        originalInvoice.setInvoiceType(vmsFullOutInvoiceDetails.getFppz());
        originalInvoice.setIssueDate(DateUtils.formatDate(vmsFullOutInvoiceDetails.getKprq(), CommonConstant.DATE_FORMAT_8_TEXT));
        originalInvoice.setTdys(originalInvoice.getTdys());
        originalInvoice.setDeptCode(vmsFullOutInvoiceDetails.getQydjid());
        originalInvoice.setFoidid(vmsFullOutInvoiceDetails.getFoidid());
        // 发票二维码内容
        String pz = "";
        if ("01".equals(originalInvoice.getInvoiceType())) {
            // 数电专
            pz = "31";
        }
        if ("02".equals(originalInvoice.getInvoiceType())) {
            // 数电普
            pz = "32";
        }
        try {
            String ewmData = "01" + "," + pz + ",,"
                    + originalInvoice.getInvoiceNo()
                    + "," + GgUtil.JeFormat(StringUtil.toString(originalInvoice.getTaxInclusiveTotalAmount()))
                    + "," + DateUtils.formatDate(vmsFullOutInvoiceDetails.getKprq(), CommonConstant.DATE_FORMAT_8).substring(0, 10).replace("-", "")
                    + ",,";
            CrcUtil crcUtil = new CrcUtil();
            String crc = crcUtil.getCRC(ewmData);
            originalInvoice.setGraphCode(ewmData + crc);
        } catch (Exception e) {
            log.error("二维码字符串生成异常crc算法异常{}", e.getMessage());
            throw new BusinessException(ResponseEnum.INVOICE_DOWNLOAD_FAIL_04);
        }


        // 特定要素类型
        if (StringUtil.isEmpty(vmsFullOutInvoiceDetails.getTdys())) {
            originalInvoice.setTdys(TdysEnum.TDYS_00.getCode());
        } else {
            originalInvoice.setTdys(vmsFullOutInvoiceDetails.getTdys());
        }
        if (StringUtil.isNotEmpty(vmsFullOutInvoiceDetails.getCezslxdm())) {
            originalInvoice.setTaxationMethod(vmsFullOutInvoiceDetails.getCezslxdm());
        }
        if (TdysEnum.TDYS_00.getCode().equals(originalInvoice.getTdys())) {
            ArrayList<GoodsInfo> goodsInfos = new ArrayList<>();
            originalInvoice.setGoodsInfos(goodsInfos);
            for (VmsFullOutInvoiceItems vmsFullOutInvoiceItem : vmsFullOutInvoiceItems) {
                GoodsInfo goodsInfo = new GoodsInfo();
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getXmmc())) {
                    goodsInfo.setItem(vmsFullOutInvoiceItem.getXmmc());
                } else {
                    goodsInfo.setItem("");
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getGgxh())) {
                    goodsInfo.setSpecification(vmsFullOutInvoiceItem.getGgxh());
                } else {
                    goodsInfo.setSpecification("");
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getDw())) {
                    goodsInfo.setMeasurementDimension(vmsFullOutInvoiceItem.getDw());
                } else {
                    goodsInfo.setMeasurementDimension("");
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getDj())) {
                    goodsInfo.setPrice(new BigDecimal(vmsFullOutInvoiceItem.getDj()));
                } else {
                    goodsInfo.setPrice(new BigDecimal(0));
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getSl())) {
                    goodsInfo.setQuantity(new BigDecimal(vmsFullOutInvoiceItem.getSl()));
                } else {
                    goodsInfo.setQuantity(new BigDecimal(0));
                }
                if (ObjectUtil.isNotEmpty(vmsFullOutInvoiceItem.getJe())) {
                    goodsInfo.setAmount(vmsFullOutInvoiceItem.getJe());
                } else {
                    goodsInfo.setAmount(new BigDecimal(0));
                }
                if (CommonEnum.TAXATION_METHOD_0.getKey().equals(vmsFullOutInvoiceDetails.getZsfs())) {
                    // 优惠政策标识 免税
                    if (YhzcbsEnum._03.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        goodsInfo.setTaxScheme(YhzcbsEnum._03.getValue());
                        goodsInfo.setTaxAmount("***");
                    } else if (YhzcbsEnum._04.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        // 优惠政策标识 不征税
                        goodsInfo.setTaxScheme(YhzcbsEnum._04.getValue());
                        goodsInfo.setTaxAmount("");
                    } else if (vmsFullOutInvoiceItem.getSlv().compareTo(BigDecimal.ZERO) == 0) {
                        // 税率为 0
                        goodsInfo.setTaxScheme("0");
                        goodsInfo.setTaxAmount("0");
                    } else {
                        goodsInfo.setTaxScheme(StringUtil.toString(vmsFullOutInvoiceItem.getSlv()));
                        goodsInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                    }
                } else {
                    goodsInfo.setTaxScheme("***");
                    goodsInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                }
                goodsInfos.add(goodsInfo);
            }
        } else if (TdysEnum.TDYS_06.getCode().equals(originalInvoice.getTdys())) {
            ArrayList<RealEstateLeasInfo> realEstateLeasInfos = new ArrayList<>();
            originalInvoice.setRealEstateLeasInfo(realEstateLeasInfos);
            for (VmsFullOutInvoiceItems vmsFullOutInvoiceItem : vmsFullOutInvoiceItems) {
                RealEstateLeasInfo realEstateLeasInfo = new RealEstateLeasInfo();
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getXmmc())) {
                    realEstateLeasInfo.setItem(vmsFullOutInvoiceItem.getXmmc());
                } else {
                    realEstateLeasInfo.setItem("");
                }
                List<VmsFullOutInvoiceTdyw> infoByFoidid = fullOutInvoiceTdywService.getInfoByFoidid(vmsFullOutInvoiceItem.getFoidid());
                if (ObjectUtil.isNotEmpty(infoByFoidid)) {
                    VmsFullOutInvoiceTdyw tdyw = infoByFoidid.get(0);
                    realEstateLeasInfo.setPropertyCertificate(tdyw.getCqzsbh());
                    realEstateLeasInfo.setMeasurementDimension(vmsFullOutInvoiceItem.getDw());
                } else {
                    realEstateLeasInfo.setPropertyCertificate("");
                    realEstateLeasInfo.setMeasurementDimension("");
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getDj())) {
                    realEstateLeasInfo.setPrice(new BigDecimal(vmsFullOutInvoiceItem.getDj()));
                } else {
                    realEstateLeasInfo.setPrice(new BigDecimal(0));
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getSl())) {
                    realEstateLeasInfo.setQuantity(new BigDecimal(vmsFullOutInvoiceItem.getSl()));
                } else {
                    realEstateLeasInfo.setQuantity(new BigDecimal(0));
                }
                if (ObjectUtil.isNotEmpty(vmsFullOutInvoiceItem.getJe())) {
                    realEstateLeasInfo.setAmount(vmsFullOutInvoiceItem.getJe());
                } else {
                    realEstateLeasInfo.setAmount(new BigDecimal(0));
                }
                if (CommonEnum.TAXATION_METHOD_0.getKey().equals(vmsFullOutInvoiceDetails.getZsfs())) {
                    // 优惠政策标识 免税
                    if (YhzcbsEnum._03.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        realEstateLeasInfo.setTaxScheme(YhzcbsEnum._03.getValue());
                        realEstateLeasInfo.setTaxAmount("***");
                    } else if (YhzcbsEnum._04.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        // 优惠政策标识 不征税
                        realEstateLeasInfo.setTaxScheme(YhzcbsEnum._04.getValue());
                        realEstateLeasInfo.setTaxAmount("");
                    } else if (vmsFullOutInvoiceItem.getSlv().compareTo(BigDecimal.ZERO) == 0) {
                        // 税率为 0
                        realEstateLeasInfo.setTaxScheme("0");
                        realEstateLeasInfo.setTaxAmount("0");
                    } else {
                        realEstateLeasInfo.setTaxScheme(StringUtil.toString(vmsFullOutInvoiceItem.getSlv()));
                        realEstateLeasInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                    }
                } else {
                    realEstateLeasInfo.setTaxScheme("***");
                    realEstateLeasInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                }
                realEstateLeasInfos.add(realEstateLeasInfo);
            }
        } else if (TdysEnum.TDYS_05.getCode().equals(originalInvoice.getTdys())) {
            ArrayList<RealEstateSalesInfo> realEstateSalesInfos = new ArrayList<>();
            originalInvoice.setRealEstateSalesInfo(realEstateSalesInfos);
            for (VmsFullOutInvoiceItems vmsFullOutInvoiceItem : vmsFullOutInvoiceItems) {
                RealEstateSalesInfo realEstateSalesInfo = new RealEstateSalesInfo();
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getXmmc())) {
                    realEstateSalesInfo.setItem(vmsFullOutInvoiceItem.getXmmc());
                } else {
                    realEstateSalesInfo.setItem("");
                }
                List<VmsFullOutInvoiceTdyw> infoByFoidid = fullOutInvoiceTdywService.getInfoByFoidid(vmsFullOutInvoiceItem.getFoidid());
                if (ObjectUtil.isNotEmpty(infoByFoidid)) {
                    VmsFullOutInvoiceTdyw tdyw = infoByFoidid.get(0);
                    realEstateSalesInfo.setPropertyCertificate(tdyw.getCqzsbh());
                    realEstateSalesInfo.setMeasurementDimension(vmsFullOutInvoiceItem.getDw());
                } else {
                    realEstateSalesInfo.setPropertyCertificate("");
                    realEstateSalesInfo.setMeasurementDimension("");
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getDj())) {
                    realEstateSalesInfo.setPrice(new BigDecimal(vmsFullOutInvoiceItem.getDj()));
                } else {
                    realEstateSalesInfo.setPrice(new BigDecimal(0));
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getSl())) {
                    realEstateSalesInfo.setQuantity(new BigDecimal(vmsFullOutInvoiceItem.getSl()));
                } else {
                    realEstateSalesInfo.setQuantity(new BigDecimal(0));
                }
                if (ObjectUtil.isNotEmpty(vmsFullOutInvoiceItem.getJe())) {
                    realEstateSalesInfo.setAmount(vmsFullOutInvoiceItem.getJe());
                } else {
                    realEstateSalesInfo.setAmount(new BigDecimal(0));
                }
                if (CommonEnum.TAXATION_METHOD_0.getKey().equals(vmsFullOutInvoiceDetails.getZsfs())) {
                    // 优惠政策标识 免税
                    if (YhzcbsEnum._03.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        realEstateSalesInfo.setTaxScheme(YhzcbsEnum._03.getValue());
                        realEstateSalesInfo.setTaxAmount("***");
                    } else if (YhzcbsEnum._04.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        // 优惠政策标识 不征税
                        realEstateSalesInfo.setTaxScheme(YhzcbsEnum._04.getValue());
                        realEstateSalesInfo.setTaxAmount("");
                    } else if (vmsFullOutInvoiceItem.getSlv().compareTo(BigDecimal.ZERO) == 0) {
                        // 税率为 0
                        realEstateSalesInfo.setTaxScheme("0");
                        realEstateSalesInfo.setTaxAmount("0");
                    } else {
                        realEstateSalesInfo.setTaxScheme(StringUtil.toString(vmsFullOutInvoiceItem.getSlv()));
                        realEstateSalesInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                    }
                } else {
                    realEstateSalesInfo.setTaxScheme("***");
                    realEstateSalesInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                }
                realEstateSalesInfos.add(realEstateSalesInfo);
            }
        } else if (TdysEnum.TDYS_09.getCode().equals(originalInvoice.getTdys())) {
            ArrayList<PassengerTransportationInfo> passengerTransportationInfos = new ArrayList<>();
            ArrayList<PassengerInfo> passengerInfos = new ArrayList<>();
            for (VmsFullOutInvoiceItems vmsFullOutInvoiceItem : vmsFullOutInvoiceItems) {
                PassengerTransportationInfo passengerTransportationInfo = new PassengerTransportationInfo();
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getXmmc())) {
                    passengerTransportationInfo.setItem(vmsFullOutInvoiceItem.getXmmc());
                } else {
                    passengerTransportationInfo.setItem("");
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getDj())) {
                    passengerTransportationInfo.setPrice(new BigDecimal(vmsFullOutInvoiceItem.getDj()));
                } else {
                    passengerTransportationInfo.setPrice(new BigDecimal(0));
                }
                if (StringUtil.isNotEmpty(vmsFullOutInvoiceItem.getSl())) {
                    passengerTransportationInfo.setQuantity(new BigDecimal(vmsFullOutInvoiceItem.getSl()));
                } else {
                    passengerTransportationInfo.setQuantity(new BigDecimal(0));
                }
                if (ObjectUtil.isNotEmpty(vmsFullOutInvoiceItem.getJe())) {
                    passengerTransportationInfo.setAmount(vmsFullOutInvoiceItem.getJe());
                } else {
                    passengerTransportationInfo.setAmount(new BigDecimal(0));
                }
                if (CommonEnum.TAXATION_METHOD_0.getKey().equals(vmsFullOutInvoiceDetails.getZsfs())) {
                    // 优惠政策标识 免税
                    if (YhzcbsEnum._03.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        passengerTransportationInfo.setTaxScheme(YhzcbsEnum._03.getValue());
                        passengerTransportationInfo.setTaxAmount("***");
                    } else if (YhzcbsEnum._04.getKey().equals(vmsFullOutInvoiceItem.getYhzcbs())) {
                        // 优惠政策标识 不征税
                        passengerTransportationInfo.setTaxScheme(YhzcbsEnum._04.getValue());
                        passengerTransportationInfo.setTaxAmount("");
                    } else if (vmsFullOutInvoiceItem.getSlv().compareTo(BigDecimal.ZERO) == 0) {
                        // 税率为 0
                        passengerTransportationInfo.setTaxScheme("0");
                        passengerTransportationInfo.setTaxAmount("0");
                    } else {
                        passengerTransportationInfo.setTaxScheme(StringUtil.toString(vmsFullOutInvoiceItem.getSlv()));
                        passengerTransportationInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                    }
                } else {
                    passengerTransportationInfo.setTaxScheme("***");
                    passengerTransportationInfo.setTaxAmount(StringUtil.toString(vmsFullOutInvoiceItem.getSe()));
                }
                passengerTransportationInfos.add(passengerTransportationInfo);
            }
            originalInvoice.setPassengerTransportations(passengerTransportationInfos);
            List<VmsFullOutInvoiceTdyw> infoByFoidid = fullOutInvoiceTdywService.getInfoByFoidid(originalInvoice.getFoidid());
            for (VmsFullOutInvoiceTdyw tdyw : infoByFoidid) {
                PassengerInfo passengerInfo = new PassengerInfo();
                passengerInfo.setTravelers(tdyw.getCxr());
                if (ZjlxEnum.ZJLX_201.getCode().equals(tdyw.getCxrzjlxdm())) {
                    // 脱敏 例如:“130429********0013”
                    passengerInfo.setIdNumber(tdyw.getSfzjhm().substring(0, 6) + "********" + tdyw.getSfzjhm().substring(14));
                } else {
                    if (StringUtil.isNotEmpty(tdyw.getSfzjhm())) {
                        // 按长度对中间三分之一的部分进行脱敏以‘*’代替
                        int idLength = tdyw.getSfzjhm().length();
                        int maskStart = idLength / 3;
                        int maskEnd = 2 * idLength / 3;
                        String maskedPart = new String(new char[maskEnd - maskStart]).replace('\0', '*');
                        passengerInfo.setIdNumber(
                                tdyw.getSfzjhm().substring(0, maskStart) +
                                        maskedPart +
                                        tdyw.getSfzjhm().substring(maskEnd)
                        );
                    }
                }
                passengerInfo.setTravelDate(tdyw.getChuxrq());
                passengerInfo.setDeparture(tdyw.getCfd());
                passengerInfo.setDestination(tdyw.getDdd());
                passengerInfo.setGrade(tdyw.getZwdj());
                passengerInfo.setTypeTransportation(JtgjlxdmEnum.getValueByKey(tdyw.getJtgjlxdm()));
                passengerInfos.add(passengerInfo);
            }
            originalInvoice.setPassengerInfo(passengerInfos);
        }
        return originalInvoice;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Object> webImport(MultipartFile excelFile, MultipartFile zipFile, boolean confirmFlag) {
        // 判断文件是否为空
        if (excelFile == null || zipFile == null) {
            return Result.ERROR(ResponseEnum.FILE_EMPTY_ERROR);
        }

        TokenUser tokenUser = SecurityUtils.getTokenUser();
        String uuid = UUID.fastUUID().toString().replace("-", "");
        // excel文件临时存放目录
        String excelLocalPath = vmsProperties.localPath() + uuid + File.separator + excelFile.getOriginalFilename();
        // zip文件临时存放目录
        String zipLocalPath = vmsProperties.localPath() + uuid + File.separator + zipFile.getOriginalFilename();
        // zip解压后文件临时存放目录
        String unzipLocalPath = vmsProperties.localPath() + uuid + File.separator + "unzip";

        try {
            // 将文件保存在临时目录中
            FileUtil.writeFromStream(excelFile.getInputStream(), excelLocalPath);
            FileUtil.writeFromStream(zipFile.getInputStream(), zipLocalPath);

            // 读取web端开具发票主信息
            ExcelListener<VmsInvoiceExcel> excelListener1 = new ExcelListener<>();
            EasyExcel.read(FileUtil.getInputStream(excelLocalPath), VmsInvoiceExcel.class, excelListener1).headRowNumber(1).sheet(1).doRead();
            // 获取web端开具发票主信息
            List<VmsInvoiceExcel> vmsInvoiceExcelList = excelListener1.getRows();
            if (CollectionUtil.isEmpty(vmsInvoiceExcelList)) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_EMPTY_ERROR);
            }
            // 移除最后一行汇总数据
            vmsInvoiceExcelList.removeIf(vmsInvoiceExcel -> "合计行".equals(vmsInvoiceExcel.getXh()));
            if (CollectionUtil.isEmpty(vmsInvoiceExcelList)) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_EMPTY_ERROR);
            }

            // 读取web端开具发票明细信息
            ExcelListener<VmsInvoiceItemExcel> excelListener2 = new ExcelListener<>();
            EasyExcel.read(FileUtil.getInputStream(excelLocalPath), VmsInvoiceItemExcel.class, excelListener2).headRowNumber(1).sheet(0).doRead();
            // 获取web端开具发票明细信息
            List<VmsInvoiceItemExcel> vmsInvoiceItemExcelList = excelListener2.getRows();
            if (CollectionUtil.isEmpty(vmsInvoiceItemExcelList)) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_EMPTY_ERROR);
            }

            log.info("{}web端开具发票主信息；{}", LOG_MSG, JSONObject.toJSONString(vmsInvoiceExcelList));
            log.info("{}web端开具发票明细信息；{}", LOG_MSG, JSONObject.toJSONString(vmsInvoiceItemExcelList));

            // excel数据必填项、合法性校验
            List<String> errMsgList = checkWebExcelData(vmsInvoiceExcelList, vmsInvoiceItemExcelList, tokenUser.getDeptCode());
            if (CollectionUtil.isNotEmpty(errMsgList)) {
                log.error("{}web端Excel导入数据合法性校验失败：{}", LOG_MSG, JSONObject.toJSONString(errMsgList));
                return Result.ERROR(ResponseEnum.BUSINESS_EXCEL_VERIFY_ERROR, errMsgList);
            }

            // 数电发票号码不能重复
            Set<String> fphmSet = vmsInvoiceExcelList.stream().map(VmsInvoiceExcel::getSdFphm).collect(Collectors.toSet());
            if (CollectionUtil.isEmpty(fphmSet) || vmsInvoiceExcelList.size() != fphmSet.size()) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_SDFPHM_ERROR);
            }

            // 解压zip，判断版式文件是否齐全
            File unzip = ZipUtil.unzip(zipLocalPath, unzipLocalPath, Charset.forName(CommonConstant.STR_GBK));
            if (unzip == null) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_ZIP_DIFFERENT_ERROR);
            }
            // 获取压缩包下的所有文件
            List<File> fileList = FileUtil.loopFiles(unzip);

            // 校验excel数据和zip数据是否一致、是否缺失
            Result<Map<String, List<File>>> checkResult = checkZipFile(vmsInvoiceExcelList, fileList);
            if (!ResponseEnum.SUCCESS.getCode().equals(checkResult.getCode())) {
                log.error("{}web端导入校验excel数据和zip数据不通过：{}", LOG_MSG, checkResult.getMessage());
                return Result.ERROR(checkResult.getCode(), checkResult.getMessage());
            }
            // key：发票号码_购买方名称，value：发票对应的版式文件
            Map<String, List<File>> fphmFileMap = checkResult.getData();

            // 匹配状态标志、重复发票标志
            boolean ppztFlag = false, repeatFlag = false;
            // 需要导入的发票在系统中已存在并且数据来源非web端导入的发票
            List<String> notWebImportInvoiceList = new ArrayList<>();
            // 校验是否存在已完成交易流水匹配的发票数据、已开发票表中是否包含重复数据
            for (VmsInvoiceExcel vmsInvoiceExcel : vmsInvoiceExcelList) {
                LambdaQueryWrapper<VmsFullOutInvoiceDetails> query = new LambdaQueryWrapper<>();
                query.select(VmsFullOutInvoiceDetails::getPpzt, VmsFullOutInvoiceDetails::getSjly);
                query.eq(VmsFullOutInvoiceDetails::getFphm, vmsInvoiceExcel.getSdFphm());
                VmsFullOutInvoiceDetails one = this.getOne(query);
                if (one != null) {
                    if (!CommonEnum.DATA_SOURCE_99.getKey().equals(one.getSjly())) {
                        notWebImportInvoiceList.add(vmsInvoiceExcel.getSdFphm());
                    }
                    repeatFlag = true;
                    if (CommonEnum.MATCHING_STATUS_1.getKey().equals(one.getPpzt())) {
                        ppztFlag = true;
                    }
                }
            }

            // 系统中已存在非web端导入的发票，不允许导入
            if (CollectionUtil.isNotEmpty(notWebImportInvoiceList)) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_SJLY_ERROR.getCode(),
                        String.format(ResponseEnum.WEB_EXCEL_SJLY_ERROR.getMsg(), String.join("，", notWebImportInvoiceList)));
            }
            // 匹配状态标志为true，返回错误信息
            if (ppztFlag) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_PPZT_ERROR);
            }
            // 重复发票标志为true且用户未进行二次确认，返回提示信息
            if (repeatFlag && !confirmFlag) {
                return Result.ERROR(ResponseEnum.OVERRIDE_CONFIRM_ALERT);
            }

            // 保存发票数据
            for (VmsInvoiceExcel vmsInvoiceExcel : vmsInvoiceExcelList) {
                // 重复导入删除之前的数据
                if (confirmFlag) {
                    LambdaQueryWrapper<NvatOutInvoiceDetails> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(NvatOutInvoiceDetails::getFphm, vmsInvoiceExcel.getSdFphm());
                    NvatOutInvoiceDetails nvatOutInvoiceDetails = nvatOutInvoiceDetailsMapper.selectOne(wrapper);
                    if (nvatOutInvoiceDetails != null) {
                        // 删除老系统发票主信息
                        nvatOutInvoiceDetailsMapper.deleteById(nvatOutInvoiceDetails.getOidid());
                        // 删除老系统发票明细信息
                        LambdaQueryWrapper<NvatOutInvoiceItems> wrapper2 = new LambdaQueryWrapper<>();
                        wrapper2.eq(NvatOutInvoiceItems::getOidid, nvatOutInvoiceDetails.getOidid());
                        nvatOutInvoiceItemsMapper.delete(wrapper2);
                    }

                    LambdaQueryWrapper<VmsFullOutInvoiceDetails> wrapper3 = new LambdaQueryWrapper<>();
                    wrapper3.eq(VmsFullOutInvoiceDetails::getFphm, vmsInvoiceExcel.getSdFphm());
                    VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails = this.getOne(wrapper3);
                    if (vmsFullOutInvoiceDetails != null) {
                        // 删除已开发票主信息
                        this.removeById(vmsFullOutInvoiceDetails.getFoidid());
                        // 删除已开发票明细信息
                        LambdaQueryWrapper<VmsFullOutInvoiceItems> wrapper4 = new LambdaQueryWrapper<>();
                        wrapper4.eq(VmsFullOutInvoiceItems::getFoidid, vmsFullOutInvoiceDetails.getFoidid());
                        fullOutInvoiceItemsService.remove(wrapper4);
                        // 删除已开发票非必填扩展信息
                        LambdaQueryWrapper<VmsFullOutInvoiceItemsExp> wrapper5 = new LambdaQueryWrapper<>();
                        wrapper5.eq(VmsFullOutInvoiceItemsExp::getFoidid, vmsFullOutInvoiceDetails.getFoidid());
                        fullOutInvoiceItemsExpService.remove(wrapper5);
                    }
                }
                // 转换为已开发票主信息
                VmsFullOutInvoiceDetails vmsFullOutInvoiceDetails = convertToDetails(vmsInvoiceExcel, tokenUser);
                // 插入老系统发票主信息表并获取主键id
                Long oidId = nvatOutInvoiceService.insertNvatOutInvoiceDetails(vmsFullOutInvoiceDetails, tokenUser.getDeptCode(), null);
                vmsFullOutInvoiceDetails.setOidid(oidId);
                log.info("{}web端导入保存数电发票主信息", LOG_MSG);
                this.save(vmsFullOutInvoiceDetails);

                // 查找对应的web端开具发票明细信息，并以序号升序排序
                List<VmsInvoiceItemExcel> invoiceItemExcelList = vmsInvoiceItemExcelList.stream().filter(a -> vmsInvoiceExcel.getSdFphm().equals(a.getSdFphm()))
                        .sorted(Comparator.comparing(p -> Long.parseLong(p.getXh()))).collect(Collectors.toList());
                // 转换为已开发票明细信息
                List<VmsFullOutInvoiceItems> vmsFullOutInvoiceItemsList = convertToItems(invoiceItemExcelList);
                Long foidId = vmsFullOutInvoiceDetails.getFoidid();
                for (VmsFullOutInvoiceItems vmsFullOutInvoiceItem : vmsFullOutInvoiceItemsList) {
                    vmsFullOutInvoiceItem.setFoidid(foidId);
                    vmsFullOutInvoiceItem.setOidid(oidId);
                    // 插入老系统发票明细信息表并获取主键id
                    Long iviId = nvatOutInvoiceService.insertNvatOutInvoiceItems(vmsFullOutInvoiceItem, oidId);
                    vmsFullOutInvoiceItem.setIviid(iviId);
                    vmsFullOutInvoiceItem.setCreatTime(new Date());
                    vmsFullOutInvoiceItem.setCreatBy(tokenUser.getUserCode());
                    log.info("{}web端导入保存数电发票明细信息", LOG_MSG);
                    fullOutInvoiceItemsService.save(vmsFullOutInvoiceItem);
                }

                // 购买方自然人标志、区域代码赋值
                VmsFullOutInvoiceItemsExp invoiceItemsExp = new VmsFullOutInvoiceItemsExp();
                invoiceItemsExp.setGmfzrrbz(CommonConstant.STR_YES.equals(vmsInvoiceExcel.getGmfzrrbz()) ? CommonEnum.PERSON_FLAG_01.getKey() : CommonEnum.PERSON_FLAG_02.getKey());
                // 查询不到数电管理信息会抛出异常
                VmsFullBswjManager bswjManager = fullBswjManagerService.getOneByWhjg(tokenUser.getDeptCode());
                invoiceItemsExp.setQydm(bswjManager.getQydm());
                invoiceItemsExp.setFoidid(foidId);
                log.info("{}web端导入保存数电非必填扩展信息", LOG_MSG);
                fullOutInvoiceItemsExpService.save(invoiceItemsExp);
            }

            // 保存web端导入的原始文件和版式文件
            saveOriginalFileAndLayoutFile(uuid, excelLocalPath, zipLocalPath, vmsInvoiceExcelList, fphmFileMap, tokenUser);

        } catch (BusinessException e) {
            log.error("{}web端开具发票导入异常，code：{}，msg：{}", LOG_MSG, e.getCode(), e.getMsg());
            throw new BusinessException(e.getCode(), e.getMsg());
        } catch (Exception e) {
            log.error("{}web端开具发票导入异常", LOG_MSG, e);
            throw new BusinessException(ResponseEnum.BUSINESS_EXCEL_READ_ERROR);
        } finally {
            // 删除临时文件
            FileUtil.del(vmsProperties.localPath() + uuid);
        }

        return Result.OK_MSG("导入成功");
    }

    /**
     * web端excel导入数据必填项、合法性校验
     *
     * @param vmsInvoiceExcelList     web端开具发票主信息
     * @param vmsInvoiceItemExcelList web端开具发票明细信息
     * @param deptCode                机构编码
     * @return 错误原因
     */
    private List<String> checkWebExcelData(List<VmsInvoiceExcel> vmsInvoiceExcelList, List<VmsInvoiceItemExcel> vmsInvoiceItemExcelList, String deptCode) {
        List<String> errMsgList = new ArrayList<>();

        /**
         * 校验web端Excel导入-发票主信息
         */
        if (CollectionUtil.isNotEmpty(vmsInvoiceExcelList)) {
            VmsEnterpriseInfo vmsEnterpriseInfo = enterpriseInfoService.getInfoByRedis(deptCode);
            if (vmsEnterpriseInfo == null) {
                throw new BusinessException(ResponseEnum.ENTERPRISEINFO_ERROR);
            }

            for (int i = 0; i < vmsInvoiceExcelList.size(); i++) {
                String errMsg = "发票基础信息-第" + (i + 1) + "行：";
                VmsInvoiceExcel vmsInvoiceExcel = vmsInvoiceExcelList.get(i);

                // 参数校验
                String msg;
                boolean isError = false;

                // 序号
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getXh(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_XH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票代码
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getFpdm(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_FPDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票号码
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getFphm(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_FPHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 数电发票号码
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getSdFphm(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_SDFPHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方纳税人识别号
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getXsfnsrsbh(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_XSFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }
                if (!vmsEnterpriseInfo.getNsrsbh().equals(vmsInvoiceExcel.getXsfnsrsbh())) {
                    msg = ResponseEnum.WEB_EXCEL_XSFNSRSBH_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方名称
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getXsfmc(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_XSFMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }
                if (!vmsEnterpriseInfo.getNsrmc().equals(vmsInvoiceExcel.getXsfmc())) {
                    msg = ResponseEnum.WEB_EXCEL_XSFMC_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方纳税人识别号
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getGmfnsrsbh(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_GMFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方名称
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getGmfmc(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_GMFMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开票日期
                try {
                    DateUtil.parse(vmsInvoiceExcel.getKprq(), CommonConstant.DATE_FORMAT_14);
                } catch (Exception e) {
                    msg = ResponseEnum.WEB_EXCEL_KPRQ_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 合计金额
                msg = checkDataService.checkBigDecimalParam(vmsInvoiceExcel.getHjje(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_HJJE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 合计税额
                msg = checkDataService.checkBigDecimalParam(vmsInvoiceExcel.getHjse(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_HJSE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 价税合计
                msg = checkDataService.checkBigDecimalParam(vmsInvoiceExcel.getJshj(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_JSHJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票来源
                if (!CommonConstant.DZFP_FWPT.equals(vmsInvoiceExcel.getFply())) {
                    msg = ResponseEnum.WEB_EXCEL_FPLY_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票票种
                if (!CommonConstant.FPPZ_01.equals(vmsInvoiceExcel.getFppz()) && !CommonConstant.FPPZ_02.equals(vmsInvoiceExcel.getFppz())) {
                    msg = ResponseEnum.WEB_EXCEL_FPPZ_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票状态
                if (!CommonConstant.NORMAL.equals(vmsInvoiceExcel.getFpzt())) {
                    msg = ResponseEnum.WEB_EXCEL_FPZT_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 是否正数发票
                if (!CommonConstant.STR_YES.equals(vmsInvoiceExcel.getSfzsfp())) {
                    msg = ResponseEnum.WEB_EXCEL_SFZSFP_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票风险等级
                if (!CommonConstant.NORMAL.equals(vmsInvoiceExcel.getFpfxdj())) {
                    msg = ResponseEnum.WEB_EXCEL_FPFXDJ_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开票人
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getKpr(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_KPR);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 备注
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getBz(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_BZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方自然人标志
                msg = checkDataService.checkStringParam(vmsInvoiceExcel.getGmfzrrbz(), CheckParamEnum.CHECK_WEB_INVOICE_EXCEL_GMFZRRBZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        /**
         * 校验web端Excel导入-发票明细信息
         */
        if (CollectionUtil.isNotEmpty(vmsInvoiceItemExcelList)) {
            VmsEnterpriseInfo vmsEnterpriseInfo = enterpriseInfoService.getInfoByRedis(deptCode);
            if (vmsEnterpriseInfo == null) {
                throw new BusinessException(ResponseEnum.ENTERPRISEINFO_ERROR);
            }

            for (int i = 0; i < vmsInvoiceItemExcelList.size(); i++) {
                String errMsg = "汇总信息表-第" + (i + 1) + "行：";
                VmsInvoiceItemExcel vmsInvoiceItemExcel = vmsInvoiceItemExcelList.get(i);

                // 参数校验
                String msg;
                boolean isError = false;

                // 序号
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getXh(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_XH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票代码
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getFpdm(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_FPDM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票号码
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getFphm(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_FPHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 数电发票号码
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getSdFphm(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_SDFPHM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方纳税人识别号
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getXsfnsrsbh(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_XSFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }
                if (!vmsEnterpriseInfo.getNsrsbh().equals(vmsInvoiceItemExcel.getXsfnsrsbh())) {
                    msg = ResponseEnum.WEB_EXCEL_XSFNSRSBH_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 销售方名称
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getXsfmc(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_XSFMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }
                if (!vmsEnterpriseInfo.getNsrmc().equals(vmsInvoiceItemExcel.getXsfmc())) {
                    msg = ResponseEnum.WEB_EXCEL_XSFMC_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方纳税人识别号
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getGmfnsrsbh(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_GMFNSRSBH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 购买方名称
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getGmfmc(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_GMFMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开票日期
                try {
                    DateUtil.parse(vmsInvoiceItemExcel.getKprq(), CommonConstant.DATE_FORMAT_14);
                } catch (Exception e) {
                    msg = ResponseEnum.WEB_EXCEL_KPRQ_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 商品和服务税收分类合并编码
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getSphfwssflhbbm(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_SPHFWSSFLHBBM);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 特定业务类型
                if (StringUtils.isNotBlank(vmsInvoiceItemExcel.getTdys())) {
                    msg = ResponseEnum.WEB_EXCEL_TDYS_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 项目名称
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getXmmc(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_XMMC);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 规格型号
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getGgxh(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_GGXH);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 单位
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getDw(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_DW);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 数量
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getSl(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_SL);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 单价
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getDj(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_DJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 金额
                msg = checkDataService.checkBigDecimalParam(vmsInvoiceItemExcel.getJe(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_JE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税率
                if (StringUtils.isBlank(vmsInvoiceItemExcel.getSlv()) || (StringUtils.isNotBlank(vmsInvoiceItemExcel.getSlv())
                        && !vmsInvoiceItemExcel.getSlv().endsWith("%"))) {
                    msg = ResponseEnum.WEB_EXCEL_SLV_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 税额
                msg = checkDataService.checkBigDecimalParam(vmsInvoiceItemExcel.getSe(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_SE);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 价税合计
                msg = checkDataService.checkBigDecimalParam(vmsInvoiceItemExcel.getJshj(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_JSHJ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票来源
                if (!CommonConstant.DZFP_FWPT.equals(vmsInvoiceItemExcel.getFply())) {
                    msg = ResponseEnum.WEB_EXCEL_FPLY_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票票种
                if (!CommonConstant.FPPZ_01.equals(vmsInvoiceItemExcel.getFppz()) && !CommonConstant.FPPZ_02.equals(vmsInvoiceItemExcel.getFppz())) {
                    msg = ResponseEnum.WEB_EXCEL_FPPZ_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票状态
                if (!CommonConstant.NORMAL.equals(vmsInvoiceItemExcel.getFpzt())) {
                    msg = ResponseEnum.WEB_EXCEL_FPZT_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 是否正数发票
                if (!CommonConstant.STR_YES.equals(vmsInvoiceItemExcel.getSfzsfp())) {
                    msg = ResponseEnum.WEB_EXCEL_SFZSFP_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 发票风险等级
                if (!CommonConstant.NORMAL.equals(vmsInvoiceItemExcel.getFpfxdj())) {
                    msg = ResponseEnum.WEB_EXCEL_FPFXDJ_ERROR.getMsg();
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 开票人
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getKpr(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_KPR);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 备注
                msg = checkDataService.checkStringParam(vmsInvoiceItemExcel.getBz(), CheckParamEnum.CHECK_WEB_INVOICE_ITEM_EXCEL_BZ);
                if (StringUtils.isNotBlank(msg)) {
                    errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                    isError = true;
                }

                // 计税方法
                if (StringUtils.isNotBlank(vmsInvoiceItemExcel.getJsff())) {
                    String key = JsffEnum.getKeyByValue(vmsInvoiceItemExcel.getJsff());
                    if (StringUtils.isBlank(key)) {
                        msg = ResponseEnum.WEB_EXCEL_JSFF_ERROR.getMsg();
                        errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                        isError = true;
                    }
                }

                // 征税项目
                if (StringUtils.isNotBlank(vmsInvoiceItemExcel.getZsxm())) {
                    String key = ZsxmEnum.getKeyByValue(vmsInvoiceItemExcel.getZsxm());
                    if (StringUtils.isBlank(key)) {
                        msg = ResponseEnum.WEB_EXCEL_ZSXM_ERROR.getMsg();
                        errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                        isError = true;
                    }
                }

                // 优惠政策标识
                if (StringUtils.isNotBlank(vmsInvoiceItemExcel.getYhzcbs())) {
                    String key = YhzcbsEnum.getKeyByValue(vmsInvoiceItemExcel.getYhzcbs());
                    if (StringUtils.isBlank(key)) {
                        msg = ResponseEnum.WEB_EXCEL_YHZCBS_ERROR.getMsg();
                        errMsg = errMsg + msg + CommonConstant.STRING_COMMA;
                        isError = true;
                    }
                }

                if (isError) {
                    if (errMsg.endsWith(CommonConstant.STRING_COMMA)) {
                        errMsg = errMsg.substring(0, errMsg.lastIndexOf(CommonConstant.STRING_COMMA));
                    }
                    errMsgList.add(errMsg);
                }
            }
        }

        return errMsgList;
    }

    /**
     * 校验excel数据和zip数据是否一致、是否缺失
     *
     * @param vmsInvoiceExcelList web端开具发票主信息
     * @param fileList            zip解压后文件
     * @return Map<String, List < File>> fphmFileMap key：发票号码_购买方名称，value：版式文件
     */
    private Result<Map<String, List<File>>> checkZipFile(List<VmsInvoiceExcel> vmsInvoiceExcelList, List<File> fileList) {
        // 数据为空校验
        if (CollectionUtil.isEmpty(vmsInvoiceExcelList) || CollectionUtil.isEmpty(fileList)) {
            return Result.ERROR(ResponseEnum.WEB_EXCEL_ZIP_DIFFERENT_ERROR);
        }

        // 校验zip文件名是否正确
        Map<String, List<File>> fphmFileMap = new HashMap<>();
        Iterator<File> iterator = fileList.iterator();
        while (iterator.hasNext()) {
            File file = iterator.next();
            // 当文件为excel时，移除当前数据
            if (file.getName().endsWith(".xls") || file.getName().endsWith(".xlsx")
                    || file.getName().endsWith(".XLS") || file.getName().endsWith(".XLSX")) {
                iterator.remove();
                continue;
            }
            // 文件名：dzfp_20位发票号码_购买方名称_14位时间串
            String regex = "dzfp_\\d{20}_(.+)_\\d{14}";
            if (!Pattern.matches(regex, FileUtil.getPrefix(file))) {
                return Result.ERROR(ResponseEnum.WEB_ZIP_FILENAME_ERROR);
            }
            String fphm = file.getName().split("_")[1];
            String gmfmc = file.getName().split("_")[2];
            // map的key为：发票号码_购买方名称
            String mapKey = fphm + "_" + gmfmc;
            List<File> files = fphmFileMap.get(mapKey);
            if (files == null) {
                List<File> files1 = new ArrayList<>();
                files1.add(file);
                fphmFileMap.put(mapKey, files1);
            } else {
                files.add(file);
                fphmFileMap.put(mapKey, files);
            }
        }

        // 校验excel数据和zip数据是否一致、是否缺失
        if (vmsInvoiceExcelList.size() != fphmFileMap.size()) {
            return Result.ERROR(ResponseEnum.WEB_EXCEL_ZIP_DIFFERENT_ERROR);
        }

        for (VmsInvoiceExcel vmsInvoiceExcel : vmsInvoiceExcelList) {
            String mapKey = vmsInvoiceExcel.getSdFphm() + "_" + vmsInvoiceExcel.getGmfmc();
            List<File> files = fphmFileMap.get(mapKey);
            if (files == null || files.size() > 3) {
                return Result.ERROR(ResponseEnum.WEB_EXCEL_ZIP_DIFFERENT_ERROR);
            }
            // 校验是否有pdf、ofd、xml三种版式文件
            int pdfCount = 0, ofdCount = 0, xmlCount = 0;
            for (File file : files) {
                // 获取文件扩展名
                String suffix = FileUtil.getSuffix(file);
                if ("pdf".equals(suffix) || "PDF".equals(suffix)) {
                    pdfCount = pdfCount + 1;
                }
                if ("ofd".equals(suffix) || "OFD".equals(suffix)) {
                    ofdCount = ofdCount + 1;
                }
                if ("xml".equals(suffix) || "XML".equals(suffix)) {
                    xmlCount = xmlCount + 1;
                }
            }
            if (pdfCount != 1 || ofdCount != 1 || xmlCount != 1) {
                return Result.ERROR(ResponseEnum.WEB_ZIP_MISS_ERROR);
            }
        }

        return Result.OK(fphmFileMap);
    }

    /**
     * 将web端excel导入发票主信息转换为已开发票主信息
     *
     * @param vmsInvoiceExcel web端导入发票主信息
     * @param tokenUser       登录用户信息
     * @return 已开发票主信息
     */
    private VmsFullOutInvoiceDetails convertToDetails(VmsInvoiceExcel vmsInvoiceExcel, TokenUser tokenUser) {
        VmsFullOutInvoiceDetails invoiceDetails = new VmsFullOutInvoiceDetails();
        invoiceDetails.setFphm(vmsInvoiceExcel.getSdFphm());
        invoiceDetails.setLzfpbz(CommonConstant.STR_YES.equals(vmsInvoiceExcel.getSfzsfp()) ? CommonEnum.INVOICE_BLUE.getKey() : CommonEnum.INVOICE_RED.getKey());
        invoiceDetails.setPtbh(zldwId);
        invoiceDetails.setFppz(CommonConstant.FPPZ_01.equals(vmsInvoiceExcel.getFppz()) ? CommonEnum.INVOICE_TYPE_01.getKey() : CommonEnum.INVOICE_TYPE_02.getKey());
        invoiceDetails.setGmfmc(vmsInvoiceExcel.getGmfmc());
        invoiceDetails.setGmfnsrsbh(vmsInvoiceExcel.getGmfnsrsbh());
        invoiceDetails.setXsfmc(vmsInvoiceExcel.getXsfmc());
        invoiceDetails.setXsfnsrsbh(vmsInvoiceExcel.getXsfnsrsbh());
        invoiceDetails.setHjje(vmsInvoiceExcel.getHjje());
        invoiceDetails.setHjse(vmsInvoiceExcel.getHjse());
        invoiceDetails.setJshj(vmsInvoiceExcel.getJshj());
        invoiceDetails.setKpr(vmsInvoiceExcel.getKpr());
        invoiceDetails.setBz(vmsInvoiceExcel.getBz());
        invoiceDetails.setKprq(DateUtil.parse(vmsInvoiceExcel.getKprq(), CommonConstant.DATE_FORMAT_14));
        invoiceDetails.setSczt(CommonEnum.INVOICE_UPLOAD_STATUS_2.getKey());
        invoiceDetails.setScjg(CommonEnum.UPLOAD_RESULT_00.getValue());
        invoiceDetails.setFpzt(CommonEnum.INVOICE_STATUS_0.getKey());
        invoiceDetails.setQydjid(tokenUser.getDeptCode());
        invoiceDetails.setSjly(CommonEnum.DATA_SOURCE_99.getKey());
        invoiceDetails.setPpzt(CommonEnum.MATCHING_STATUS_0.getKey());
        invoiceDetails.setSfbdc(CommonEnum.SFBDC_NO.getKey());
        invoiceDetails.setZsfs(CommonEnum.TAXATION_METHOD_0.getKey());
        invoiceDetails.setKpzt(CommonEnum.KPZT_2.getKey());
        invoiceDetails.setDelFlag(CommonEnum.DEL_STATUS_0.getKey());
        invoiceDetails.setCreatTime(new Date());
        invoiceDetails.setCreatBy(tokenUser.getUserCode());
        invoiceDetails.setUpdateTime(new Date());
        invoiceDetails.setUpdateBy(tokenUser.getUserCode());

        return invoiceDetails;
    }

    /**
     * 将web端excel导入发票明细信息转换为已开发票明细信息
     *
     * @param vmsInvoiceItemExcelList web端导入发票明细信息
     * @return 已开发票明细信息
     */
    private List<VmsFullOutInvoiceItems> convertToItems(List<VmsInvoiceItemExcel> vmsInvoiceItemExcelList) {
        List<VmsFullOutInvoiceItems> invoiceItemList = new ArrayList<>();
        for (int i = 0; i < vmsInvoiceItemExcelList.size(); i++) {
            VmsInvoiceItemExcel vmsInvoiceItemExcel = vmsInvoiceItemExcelList.get(i);
            VmsFullOutInvoiceItems invoiceItem = new VmsFullOutInvoiceItems();
            invoiceItem.setMxxh((long) i + 1);
            invoiceItem.setXmmc(vmsInvoiceItemExcel.getXmmc());
            invoiceItem.setGgxh(vmsInvoiceItemExcel.getGgxh());
            invoiceItem.setDw(vmsInvoiceItemExcel.getDw());
            invoiceItem.setSl(vmsInvoiceItemExcel.getSl());
            invoiceItem.setDj(vmsInvoiceItemExcel.getDj());
            invoiceItem.setJe(vmsInvoiceItemExcel.getJe());
            BigDecimal slv;
            if (vmsInvoiceItemExcel.getSlv().contains("免税") || vmsInvoiceItemExcel.getSlv().contains("不征税")) {
                slv = BigDecimal.ZERO;
            } else {
                slv = new BigDecimal(vmsInvoiceItemExcel.getSlv().replace("%", "")).divide(new BigDecimal("100"), 6, RoundingMode.HALF_UP);
            }
            invoiceItem.setSlv(slv);
            invoiceItem.setSe(vmsInvoiceItemExcel.getSe());
            // 计算含税单价，老系统使用
            if (StringUtils.isNotBlank(invoiceItem.getSl())) {
                BigDecimal jshj = invoiceItem.getJe().add(invoiceItem.getSe());
                BigDecimal hsdj = jshj.divide(new BigDecimal(invoiceItem.getSl()), 6, RoundingMode.HALF_UP);
                invoiceItem.setHsdj(hsdj.stripTrailingZeros().toPlainString());
            }
            invoiceItem.setSphfwssflhbbm(vmsInvoiceItemExcel.getSphfwssflhbbm());
            invoiceItem.setFphxz(CommonEnum.FPHXZ_00.getKey());
            if (StringUtils.isBlank(vmsInvoiceItemExcel.getJsff())) {
                invoiceItem.setJsff(JsffEnum.JSFF_1.getKey());
            } else {
                invoiceItem.setJsff(JsffEnum.getKeyByValue(vmsInvoiceItemExcel.getJsff()));
            }
            if (StringUtils.isBlank(vmsInvoiceItemExcel.getZsxm())) {
                invoiceItem.setZsxm(ZsxmEnum.ZSXM_03.getKey());
            } else {
                invoiceItem.setZsxm(ZsxmEnum.getKeyByValue(vmsInvoiceItemExcel.getZsxm()));
            }
            invoiceItem.setYhzcbs(YhzcbsEnum.getKeyByValue(vmsInvoiceItemExcel.getYhzcbs()));

            invoiceItemList.add(invoiceItem);
        }

        return invoiceItemList;
    }

    /**
     * 保存web端导入的原始文件和版式文件
     *
     * @param uuid                唯一标识
     * @param excelLocalPath      excel文件临时存放路径
     * @param zipLocalPath        zip文件临时存放路径
     * @param vmsInvoiceExcelList web端开具发票主信息
     * @param fphmFileMap         版式文件map key：发票号码_购买方名称，value：发票对应的版式文件
     * @param tokenUser           用户登录信息
     */
    private void saveOriginalFileAndLayoutFile(String uuid, String excelLocalPath, String zipLocalPath, List<VmsInvoiceExcel> vmsInvoiceExcelList,
                                               Map<String, List<File>> fphmFileMap, TokenUser tokenUser) {
        // 保存web端导入的原始文件，路径：机构/年/月日/uuid
        String OriginalFilePath = vmsProperties.webImportOriginalFilePath() + tokenUser.getDeptCode() + File.separator + DateUtil.thisYear()
                + File.separator + DateUtil.format(new Date(), "MMdd") + File.separator + uuid + File.separator;
        String excelFilePath = OriginalFilePath + FileUtil.getName(excelLocalPath);
        String zipFilePath = OriginalFilePath + FileUtil.getName(zipLocalPath);
        FileUtil.copy(excelLocalPath, excelFilePath, true);
        FileUtil.copy(zipLocalPath, zipFilePath, true);

        VmsWebImportFile vmsWebImportFile = new VmsWebImportFile();
        vmsWebImportFile.setInvoiceCount((long) vmsInvoiceExcelList.size());
        vmsWebImportFile.setFilePath(OriginalFilePath);
        vmsWebImportFile.setDeptCode(tokenUser.getDeptCode());
        vmsWebImportFile.setCreatTime(new Date());
        vmsWebImportFile.setCreatBy(tokenUser.getUserCode());
        vmsWebImportFileService.save(vmsWebImportFile);

        // 保存web端导入的版式文件，路径：税号/年/月日/
        for (VmsInvoiceExcel vmsInvoiceExcel : vmsInvoiceExcelList) {
            String xsfsbh = vmsInvoiceExcel.getXsfnsrsbh();
            Date kprq = DateUtil.parse(vmsInvoiceExcel.getKprq(), CommonConstant.DATE_FORMAT_14);
            String mapKey = vmsInvoiceExcel.getSdFphm() + "_" + vmsInvoiceExcel.getGmfmc();
            List<File> fileList = fphmFileMap.get(mapKey);
            for (File file : fileList) {
                String layoutFilePath = vmsProperties.webImportLayoutFilePath() + xsfsbh + File.separator + DateUtil.format(kprq, "yyyy")
                        + File.separator + DateUtil.format(kprq, "MMdd") + File.separator + file.getName().split("_")[1] + "." + FileUtil.getSuffix(file);
                FileUtil.writeFromStream(FileUtil.getInputStream(file), layoutFilePath);
            }
        }
    }


    /**
     * 统计相关-发票信息统计
     *
     * @param invoiceInfoDto
     * @return
     */
    @Override
    public IPage<InvoiceInfoVo> queryInvoiceInfoStatistics(InvoiceInfoDto invoiceInfoDto) {
        // 创建返回对象
        Integer pageNo = invoiceInfoDto.getPageNo();
        Integer pageSize = invoiceInfoDto.getPageSize();
        IPage<InvoiceInfoVo> page = new Page<>(pageNo, pageSize);
        String [] str = invoiceInfoDto.getSxjg().split(",");
        // 查询发票信息统计
        IPage<InvoiceInfoVo> invoiceInfoVoIPage = this.baseMapper.queryInvoiceInfoStatistics(page, invoiceInfoDto,str);
        return invoiceInfoVoIPage;
    }

}
